Introduction

In 2017, the Tuveson Lab at Cold Spring Harbor Cancer Center published a paper written by Elyada et al that detailed the discovery of cancer-associated fibroblasts (CAFs) in mice. The subtypes were then validated in human samples affected with PDAC in a subsequent paper released in 2019. Here we will use SCISSORS to identify the CAF subtypes within the larger stroma population, fine-grained immune cell types within broadly-defined immune clusters, and ductal & PDAC subtypes within the ductal group. You can install SCISSORS from our GitHub repository.

Libraries

R

library(VAM)           # single cell GSEA
library(dplyr)         # tidy data 
library(Seurat)        # single cell infrastructure
library(ggplot2)       # pretty plots
library(SingleR)       # cell type assignment
library(janitor)       # clean data
library(decoderr)      # de novo deconvolution 
library(SCISSORS)      # our package
library(mixtools)      # Gaussian mixture model estimation
library(patchwork)     # align plots
library(latex2exp)     # LaTeX
library(paletteer)     # color palettes
library(CONICSmat)     # CNV estimation
library(reticulate)    # Python interface
library(kableExtra)    # pretty tables
library(wesanderson)   # more color palettes

Python

import numpy as np
from openTSNE import TSNEEmbedding
from openTSNE import initialization
from openTSNE.affinity import Multiscale
from openTSNE.affinity import PerplexityBasedNN

Data

First we load in the \(\text{gene} \times \text{cell}\) counts matrix, then create a Seurat object to hold it in. Next, we add samplename, tissue type, and patient sex metadata taken from the publicly available dataset.

raw_counts <- Read10X(data.dir = "~/Desktop/Data/Elyada Raw/All Human/")
pdac <- CreateSeuratObject(raw_counts, 
                           project = "Elyada", 
                           min.cells = 3, 
                           min.features = 500)
pdac@meta.data$sample <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "SRR9274536", 
                                   grepl("-2", rownames(pdac@meta.data)) ~ "SRR9274537", 
                                   grepl("-3", rownames(pdac@meta.data)) ~ "SRR9274538", 
                                   grepl("-4", rownames(pdac@meta.data)) ~ "SRR9274539",
                                   grepl("-5", rownames(pdac@meta.data)) ~ "SRR9274540", 
                                   grepl("-6", rownames(pdac@meta.data)) ~ "SRR9274541", 
                                   grepl("-7", rownames(pdac@meta.data)) ~ "SRR9274542", 
                                   grepl("-8", rownames(pdac@meta.data)) ~ "SRR9274543", 
                                   grepl("-9", rownames(pdac@meta.data)) ~ "SRR9274544")
pdac@meta.data$condition <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-2", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-3", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-4", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-5", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-6", rownames(pdac@meta.data)) ~ "AdjNorm", 
                                      grepl("-7", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-8", rownames(pdac@meta.data)) ~ "AdjNorm", 
                                      grepl("-9", rownames(pdac@meta.data)) ~ "PDAC")
pdac@meta.data$sex <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-2", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-3", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-4", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-5", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-6", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-7", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-8", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-9", rownames(pdac@meta.data)) ~ "female")

Next, we read in a dataset of basal-like and classical PDAC marker genes that we’ll use later on to perform enrichment analysis.

load("~/Desktop/Data/cmbSubtypes.RData")
pdac_50_genes <- subtypeGeneList[[4]]
basal_genes <- pdac_50_genes[pdac_50_genes$BasalLike, ]$geneSymbol
classical_genes <- pdac_50_genes[!pdac_50_genes$BasalLike, ]$geneSymbol

Preprocessing

We run the typical single cell pre-processing steps on our cells - normalization, dimension reduction, and clustering.

pdac <- PrepareData(seurat.object = pdac, 
                    n.HVG = 4000, 
                    n.PC = 20, 
                    regress.mt = FALSE, 
                    regress.cc = FALSE, 
                    which.dim.reduc = "tsne", 
                    initial.resolution = 0.4, 
                    random.seed = 629)
## [1] "Running t-SNE on 20 principal components with perplexity = 30"
## [1] "Found 12 unique clusters"

Let’s check out the t-SNE embedding. It looks decent, but could definitely be improved. Globally, the clusters are arranged in a blob - which isn’t very informative - though the local structure seems to have been preserved fairly well. Visually, there are several clusters that contain subgroups - clusters 3, 4, 5, 6, & 9 look like good candidates for reclustering.

p0 <- DimPlot(pdac, reduction = "tsne", pt.size = 0.75) + 
      scale_color_paletteer_d("ggthemes::Classic_20") + 
      labs(x = "t-SNE 1", y = "t-SNE 2") + 
      theme_yehlab() + 
      theme(legend.text = element_text(size = 10)) + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p0

We compute the distribution of the silhouette scores for each cluster.

sil_df <- ComputeSilhouetteScores(pdac, avg = FALSE)
p1 <- ggplot(sil_df, aes(x = Cluster, y = Score, fill = Cluster)) + 
      geom_violin(draw_quantiles = .5, color = "black", scale = "width") + 
      scale_fill_paletteer_d("ggthemes::Classic_20") + 
      labs(y = "Silhouette Score", x = "Louvain Clusters", fill = NULL) + 
      theme_minimal() + 
      theme(panel.grid = element_blank(), 
            panel.border = element_rect(fill = NA, size = 1), 
            legend.position = "none", 
            axis.title.x = element_text(size = 22), 
            axis.title.y = element_text(size = 22), 
            axis.text = element_text(size = 16), 
            axis.ticks = element_line(), 
            plot.subtitle = element_text(face = "italic", size = 10))

Looking at the silhouette score distribution for each cluster, we see that Cluster 10 seems to have the best fit, and Clusters 1, 2, & 9 seem to have pretty poor fits.

p1

Lastly, we’ll identify marker genes for each of the clusters.

pdac_markers <- FindAllMarkers(pdac, 
                               logfc.threshold = 2, 
                               test.use = "wilcox", 
                               only.pos = TRUE, 
                               random.seed = 629, 
                               verbose = FALSE) %>% 
                filter(p_val_adj < .05) 
top5_pdac_markers <- pdac_markers %>% 
                     group_by(cluster) %>% 
                     arrange(desc(avg_log2FC)) %>% 
                      slice_head(n = 5)
p2 <- DotPlot(pdac, features = unique(top5_pdac_markers$gene), dot.scale = 15) + 
      scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
      labs(color = "Expression", size = "% Expressed", y = "Louvain Cluster") + 
      theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
            legend.position = "right", legend.justification = "center", 
            panel.border = element_rect(fill = NA, size = 1, color = "black"), 
            axis.line = element_blank(), 
            legend.title = element_text(size = 18), 
            axis.title.x = element_blank(), 
            axis.title.y = element_text(size = 20), 
            axis.text.y = element_text(size = 18)) + 
      guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
             size = guide_legend(title.position = "top", title.hjust = 0.5))
p2

Optimize Dimension Reduction

I think the two-dimensional visualization of the cells could be improved. We’ll try using UMAP and the Fast Fourier Transform-accelerated Fit-SNE (as implemented in the openTSNE library) to improve the embedding.

UMAP

It seems like UMAP does a good job of clearly separating our clusters and preserving the global structure of the data. However, it’s difficult to see local structure within some of the clusters due to their density.

pdac <- RunUMAP(pdac, 
                reduction = "pca", 
                dims = 1:20, 
                umap.method = "uwot", 
                n.components = 2, 
                n.epochs = 750, 
                n.neighbors = 50, 
                metric = "cosine", 
                seed.use = 629, 
                verbose = FALSE)
p3 <- DimPlot(pdac, reduction = "umap", pt.size = 0.75) + 
      scale_color_paletteer_d("ggthemes::Classic_20") + 
      labs(x = "UMAP 1", y = "UMAP 2") + 
      theme_yehlab() +
      theme(legend.text = element_text(size = 10)) + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p3

Fit-SNE

For information on how to install the openTSNE implementation of Fit-SNE and how to run the algorithm, please visit the excellent GitHub repository of Pavlin Policar.

First we’ll run a simple, standard Fit-SNE embedding. It’s necessary to make the PCA embeddings accessible by Python.

pc_df <- Embeddings(pdac, reduction = "pca")
# import data
pc_df = np.array(r.pc_df)
# run Fit-SNE
affin = PerplexityBasedNN(pc_df, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(pc_df, random_state=629)
tsne1 = TSNEEmbedding(init, affin, negative_gradient_method='fft')
embed1 = tsne1.optimize(n_iter=350, exaggeration=12, momentum=0.6) 
embed2 = embed1.optimize(n_iter=750, momentum=0.8)

The embedding looks good, so we’ll use it going forwards.

embed <- as.matrix(py$embed2)
rownames(embed) <- colnames(pdac)
pdac@reductions$fitsne <- CreateDimReducObject(embeddings = embed, 
                                               key = "FitSNE_", 
                                               assay = "SCT", 
                                               global = TRUE)
p4 <- DimPlot(pdac, reduction = "fitsne", pt.size = 0.75) + 
      scale_color_paletteer_d("ggthemes::Classic_20") + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme_yehlab() +
      theme(legend.text = element_text(size = 10)) + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p4

Due to the way Seurat accesses cell embeddings, we’ll need to replace our original t-SNE dimension reduction in our Seurat object with the new Fit-SNE version. We’ll keep the original Barnes-Hut t-SNE embedding under a separate name.

pdac@reductions$bh_tsne <- pdac@reductions$tsne
pdac@reductions$tsne <- pdac@reductions$fitsne

SingleR Cell Type Identification

Single Cell RNA-seq Reference Data

Here we use the SingleR package to identify broad cell types. The reference dataset we load is an sctransform-normalized version of the raw counts available in scRNAseq::BaronPancreasData(), which consists of normal pancreas cells that were sequenced and annotated by the researchers.

sc_ref <- readRDS("/Volumes/labs/Home/Jen Jen Yeh Lab/Jack/scRNAseq/Seurat/single_cell_ref_normalized.Rds")
sc_preds <- SingleR(test = data.frame(pdac@assays$SCT@data), 
                    ref = sc_ref, 
                    labels = sc_ref$label, 
                    method = "cluster", 
                    clusters = pdac$seurat_clusters, 
                    de.method = "wilcox")
pdac[["SingleR.labels.sc"]] <- sc_preds$labels[match(pdac[[]][["seurat_clusters"]], rownames(sc_preds))]
pdac$SingleR.labels.sc <- case_when(pdac$SingleR.labels.sc == "acinar" ~ "Acinar", 
                                    pdac$SingleR.labels.sc == "activated_stellate" ~ "Activated Stellate",
                                    pdac$SingleR.labels.sc == "ductal" ~ "Ductal", 
                                    pdac$SingleR.labels.sc == "macrophage" ~ "Macrophage",
                                    pdac$SingleR.labels.sc == "t_cell" ~ "T")

We can see that there’s a large immune population, as well as smaller ductal, fibroblast (denoted activated stellate in the reference dataset), and acinar groups. These broad cell types line up with what we expected to see given the authors’ original cell cluster annotations.

p5 <- DimPlot(pdac, reduction = "tsne", group.by = "SingleR.labels.sc", pt.size = 0.75) + 
      scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p5

Bulk Tissue RNA-seq Reference Data

This dataset is composed of labeled & log-normalized bulk RNA-seq samples from the Human Primary Cell Atlas.

bulk_ref <- HumanPrimaryCellAtlasData()
bulk_preds <- SingleR(test = data.frame(pdac@assays$SCT@data), 
                      ref = bulk_ref, 
                      labels = bulk_ref$label.main, 
                      method = "cluster", 
                      clusters = pdac$seurat_clusters, 
                      de.method = "wilcox")
pdac[["SingleR.labels.bulk"]] <- bulk_preds$labels[match(pdac[[]][["seurat_clusters"]], rownames(bulk_preds))]
pdac$SingleR.labels.bulk <- case_when(pdac$SingleR.labels.bulk == "B_cell" ~ "B", 
                                      pdac$SingleR.labels.bulk == "Epithelial_cells" ~ "Epithelial", 
                                      pdac$SingleR.labels.bulk == "B_cell-" ~ "B", 
                                      pdac$SingleR.labels.bulk == "T_cells" ~ "T",
                                      TRUE ~ pdac$SingleR.labels.bulk)

The bulk reference gives us somewhat more granular labels for the immune cells, and confirms the identities of the ductal / epithelial and stroma clusters.

p6 <- DimPlot(pdac, reduction = "tsne", group.by = "SingleR.labels.bulk", pt.size = 0.75) + 
      scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p6

One shouldn’t use SingleR as the final authority for cell types, but we were able to confirm the identities of the ductal and fibroblast clusters, which is important for this dataset as the cells we are most interested in are the cancer-associated fibroblasts (CAFs).

CONICSmat CNV Estimation

Next we’ll attempt to identify malignant cells using single-cell copy number variation estimation as implemented in the CONCISmat package. Details of the GMM methodology used can be found at the Diaz Lab’s GitHub repository. Note: this step is memory-intensive because 1) it requires the sparse counts matrix to be cast to a dense matrix and 2) a lot of Gaussian mixture models get estimated. If your machine doesn’t have a lot of RAM it might be best to skip this and manually annotate the malignant cells instead through the usage of canonical markers or the VAM single-cell GSEA methodology.

chrom_regions <- read.table("/Volumes/labs/Home/Jen Jen Yeh Lab/Jack/scRNAseq/chrom_arm_positions.txt", 
                            sep = "\t", 
                            row.names = 1, 
                            header = TRUE)
gene_pos <- getGenePositions(rownames(pdac))
cpm <- t(t(as.matrix(pdac@assays$SCT@counts)) / colSums(as.matrix(pdac@assays$SCT@counts))) * 10^5
cpm <- log2(cpm + 1)
norm_factor <- calcNormFactors(cpm)
cnv_est <- plotAll(mat = cpm, 
                   normFactor = norm_factor, 
                   regions = chrom_regions, 
                   gene_pos = gene_pos, 
                   fname = "Elyada")

Visualizing CNVs

After estimating CNVs, we cluster the cells into \(k = 3\) clusters, with the hope of finding one large cluster of normal cells and two smaller clusters composed of CAFs and PDAC cells.

bic_table <- read.table("./Elyada_BIC_LR.txt", 
                        sep = "\t", 
                        row.names = 1, 
                        header = TRUE, 
                        check.names = FALSE)
cand_regions <- rownames(bic_table[bic_table$`BIC difference` > 1000 & bic_table$`LRT adj. p-val` < .01, ])
pdf("~/Desktop/R/SCISSORS/vignettes/figures_supp/Elyada/CONICSmat_Heatmap.pdf", width = 12, height = 6)
hist1 <- plotHistogram(cnv_est[, cand_regions], 
                       cpm, 
                       clusters = 3, 
                       zscoreThreshold = 3, 
                       celltypes = pdac$SingleR.labels.bulk, 
                       patients = pdac$sample)
dev.off()
## pdf 
##   3

We add the normal vs. malignant cell labels in to our Seurat object’s metadata, then visualize the results. As expected, the malignant cells are located in the clusters identified by SingleR as ductal cells and fibroblasts. This indicates that CONICSmat did a solid job of estimating the CNVs - no easy feat with sparse, noisy single-cell data.

normal <- which(hist1 == 1)
malignant <- which(hist1 != 1)
pdac@meta.data$malig <- ifelse(rownames(pdac@meta.data) %in% names(normal), "Normal", "Malignant")
p7 <- DimPlot(pdac, reduction = "tsne", group.by = "malig", pt.size = 0.75) + 
      scale_color_manual(values = wes_palette("Zissou1", n = 5)[c(5, 2)]) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p7

When looking at the SingleR labels from the bulk reference, we see that the Epithelial (Ductal) and Mesenchymal Stem Cell (Fibroblast) clusters have the highest proportions of malignant cells, which is exactly what we expected to see.

pdac@meta.data %>% 
  group_by(SingleR.labels.bulk) %>% 
  summarise(MeanMalig = mean(case_when(malig == "Malignant" ~ 1, TRUE ~ 0))) %>% 
  mutate(MeanMalig = formattable::percent(MeanMalig)) %>% 
  kbl(booktabs = TRUE, col.names = c("Bulk Reference SingleR Label", "% Malignant Cells")) %>% 
  kable_minimal(full_width = FALSE)
Bulk Reference SingleR Label % Malignant Cells
B 0.11%
Epithelial 47.02%
GMP 0.71%
Macrophage 6.21%
Monocyte 2.45%
MSC 41.33%
T 0.42%

DECODER

Next, we use Dr. Xianlu Peng’s DECODER in order to deconvolve the dataset and assign weights to each cell using non-negative matrix factorization. We calculate basal & classical PDAC, normal & activated stroma, immune, and endocrine & exocrine pancreas compartment weights.

sample_wts_unscaled <- Decon_single_sample(refSet = "TCGA_RNAseq_PAAD", 
                                           data = pdac@assays$SCT@data, 
                                           geneIDType = "geneSymbol")
sample_wts <- Norm_PDAC_weights(sample_wts_unscaled)
pdac <- AddMetaData(pdac, sample_wts$Immune, "immune")
pdac <- AddMetaData(pdac, sample_wts$bcRatio, "bc_ratio")
pdac <- AddMetaData(pdac, sample_wts$Exocrine, "exocrine")
pdac <- AddMetaData(pdac, sample_wts$Endocrine, "endocrine")
pdac <- AddMetaData(pdac, sample_wts_unscaled[, 9], "basal")
pdac <- AddMetaData(pdac, sample_wts_unscaled[, 5], "classical")
pdac <- AddMetaData(pdac, sample_wts$NormalStroma, "norm_stroma")
pdac <- AddMetaData(pdac, sample_wts$ActivatedStroma, "act_stroma")

Visualizing DECODER Weights

Basal PDAC

The basal weights are highest in a subcluster of the ductal group identified through SingleR. This is interesting as the authors did not find evidence of the basal subtype in their paper.

p8 <- FeaturePlot(pdac, reduction = "tsne", features = "basal", pt.size = 0.75) + 
      scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      NoLegend()
p8

Classical PDAC

The classical weights are highest in another subcluster of the ductal cluster, and cells with high classical weights do not collocate with those that have high basal weights. The putative classical and basal PDAC cells also align closely with the cells identified through CONCISmat as malignant.

p9 <- FeaturePlot(pdac, reduction = "tsne", features = "classical", pt.size = 0.75) + 
      scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      NoLegend()
p9

Exocrine Pancreas

The cluster identified through SingleR as acinar cells is the only cluster with high exocrine pancreas weights.

p10 <- FeaturePlot(pdac, reduction = "tsne", features = "exocrine", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p10

Endocrine Pancreas

No cells have high endocrine pancreas weights.

p11 <- FeaturePlot(pdac, reduction = "tsne", features = "endocrine", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p11

Immune

Once again, we confirm the largeness of the immune cell population in this dataset.

p12 <- FeaturePlot(pdac, reduction = "tsne", features = "immune", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p12

Normal Stroma

Cells with high normal stroma stroma weights are located in the cluster identified by SingleR as being stromal cells.

p13 <- FeaturePlot(pdac, reduction = "tsne", features = "norm_stroma", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p13

Activated Stroma

Cells with high activated stroma weights are also located in the fibroblast cluster, and do not intersect with the cells that have high normal stroma scores. This indicates that SCISSORS will most likely perform well on the fibroblast cluster and be able to quickly tease out the cell subtypes.

p14 <- FeaturePlot(pdac, reduction = "tsne", features = "act_stroma", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p14

SCISSORS

Now that we have rough labels from SingleR, CNVs from CONICSmat, and compartment weights from DECODER, we should have more than enough cell-level metadata to look for and annotate cell subtypes using SCISSORS.

Fibroblasts

The fibroblast marker genes provided by Elyada et al match the SingleR results defining cluster 6 as containing fibroblasts.

p15 <- FeaturePlot(pdac, reduction = "tsne", features = "COL1A1", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "COL1A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p16 <- FeaturePlot(pdac, reduction = "tsne", features = "COL3A1", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "COL3A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p17 <- FeaturePlot(pdac, reduction = "tsne", features = "LUM", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "LUM") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p18 <- FeaturePlot(pdac, reduction = "tsne", features = "DCN", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "DCN") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p15 | p16) / (p17 | p18)

Here’s the cells we’ll be reclustering.

fibro_cells <- rownames(pdac@meta.data[pdac@meta.data$seurat_clusters == 6, ])
p19 <- DimPlot(pdac, reduction = "tsne", cells.highlight = fibro_cells, cols.highlight = "navy", pt.size = 0.75) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend()
p19 / p4

Reclustering

Here we use ReclusterCells() to identify subclusters within cluster 6. We find five distinct subclusters.

fibro <- ReclusterCells(pdac,
                        which.clust = 6, 
                        n.HVG = 4000, 
                        n.PC = 20, 
                        resolution.vals = c(.03, .05, .1), 
                        k.vals = c(20, 30, 40), 
                        redo.embedding = TRUE)
fibro_pc <- Embeddings(fibro, "pca")
## [1] "Reclustering cells in cluster 6 using k = 20 & resolution = 0.03; S = 0.579"

We’ll again run Fit-SNE on the reclustered cells, for consistencies sake.

# import data
fibro_pc = r.fibro_pc
# run Fit-SNE
affin_fibro = PerplexityBasedNN(fibro_pc, perplexity=40, metric='cosine', random_state=629)
init = initialization.pca(fibro_pc, random_state=629)
tsne_f = TSNEEmbedding(init, affin_fibro, negative_gradient_method='fft')
embed_f1 = tsne_f.optimize(n_iter=250, exaggeration=5, momentum=0.4) 
embed_f2 = embed_f1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

Pulling the results back into R and visualizing them shows clear separation between the subclusters. There’s some noise in subcluster 0, but other than that the reembedding looks solid.

embed_fibro <- as.matrix(py$embed_f2)
rownames(embed_fibro) <- colnames(fibro)
fibro@reductions$bh_tsne <- fibro@reductions$tsne
fibro@reductions$tsne<- CreateDimReducObject(embeddings = embed_fibro, 
                                             key = "FitSNE_", 
                                             assay = "SCT", 
                                             global = TRUE)
p20 <- DimPlot(fibro, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p20

Cell Type Identification

First we identify the endothelial and perivascular cells using PLVAP and RGS5 expression.

p21 <- FeaturePlot(fibro, reduction = "tsne", features = "PLVAP", pt.size = 1.5) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "PLVAP") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p22 <- FeaturePlot(fibro, reduction = "tsne", features = "RGS5", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "RGS5") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p21 | p22) / p20

Next, we use the VAM method of single cell gene set enrichment analysis to determine which clusters are enriched for the iCAF and myCAF marker genes, as well as the general pan-CAF marker set. We use the marker genes identified by the authors.

icaf_genes <- c("IL6", "PDGFRA", "CXCL12", "CFD", "LMNA", "AGTR1", "HAS1", "CXCL1", "CXCL2", "CCL2", "IL8")
mycaf_genes <- c("ACTA2", "TAGLN", "MMP11", "MYL9", "HOPX", "POSTN", "TPM1", "TPM2")
pan_caf_genes <- c("COL1A1", "FAP", "PDPN", "DCN", "VIM")
gene_sets <- list(icaf_genes, mycaf_genes, pan_caf_genes)
names(gene_sets) <- c("iCAF", "myCAF", "Pan-CAF")
for (i in seq(gene_sets)) {
  gene_sets[[i]] <- gene_sets[[i]][gene_sets[[i]] %in% rownames(fibro)]
}
fibro <- vamForSeurat(fibro, 
                      gene.set.collection = gene_sets, 
                      gamma = TRUE)
DefaultAssay(fibro) <- "VAMcdf"

iCAFs & myCAFs

We can easily define cluster 0 as the myCAF population, and cluster 2 as the slightly smaller iCAF population. Cluster 4 shows no enrichment whatsoever for either the iCAF or myCAF gene sets.

p23 <- FeaturePlot(fibro, reduction = "tsne", features = "iCAF", pt.size = 1.5) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "iCAF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p24 <- FeaturePlot(fibro, reduction = "tsne", features = "myCAF", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "myCAF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p23 | p24) / p20

apCAFs

So we have a small cluster of 23 cells that does not appear to express any of the fibroblast, CAF, perivascular, or endothelial markers. After performing differential expression analysis, we find that the top 3 markers for cluster 4 are CLU, CD74, and CRYAB. Interestingly, CLU and CD74 were found to be differentially expressed in the apCAF population discovered in the KPC mouse models of CAFs in Elyada et al.

DefaultAssay(fibro) <- "SCT"
fibro_markers <- FindAllMarkers(fibro, 
                                assay = "SCT", 
                                logfc.threshold = 1.5, 
                                test.use = "wilcox", 
                                only.pos = TRUE, 
                                random.seed = 629, 
                                verbose = FALSE)
fibro_markers %>% 
  filter(cluster == 4) %>% 
  arrange(desc(avg_log2FC)) %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  slice_head(n = 5) %>% 
  kbl(booktabs = TRUE, digits = 4, row.names = FALSE) %>% 
  kable_minimal("hover", full_width = FALSE)
cluster gene avg_log2FC p_val_adj pct.1 pct.2
4 CLU 4.1036 0 1.000 0.359
4 CRYAB 4.1022 0 0.957 0.365
4 CD74 2.8741 0 0.957 0.317
4 HLA-DRA 2.5622 0 0.870 0.236
4 HLA-DRB1 2.3438 0 0.609 0.149

We re-run GSEA, again using the VAM package and the differentially expressed genes for the apCAF population as defined in Elyada et al (with the mouse gene names converted to HGNC symbols). We can see that the apCAF pathway is strongly enriched in cluster 4 as compared to the other CAF clusters.

apcaf_genes <- c("HLA-DQB1", "CD74", "SAA3P", "SLPI")
gene_sets <- list(icaf_genes, mycaf_genes, apcaf_genes, pan_caf_genes)
names(gene_sets) <- c("iCAF", "myCAF", "apCAF", "Pan-CAF")
for (i in seq(gene_sets)) {
  gene_sets[[i]] <- gene_sets[[i]][gene_sets[[i]] %in% rownames(fibro)]
}
fibro <- vamForSeurat(fibro, 
                      gene.set.collection = gene_sets, 
                      gamma = TRUE)
DefaultAssay(fibro) <- "VAMcdf"
p25 <- FeaturePlot(fibro, reduction = "tsne", features = "apCAF", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "apCAF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p25 / p20

Visualization

Finally, we add cell labels to our identified clusters.

fibro$label <- case_when(fibro$seurat_clusters == 0 ~ "myCAF", 
                         fibro$seurat_clusters == 1 ~ "Perivascular", 
                         fibro$seurat_clusters == 2 ~ "iCAF", 
                         fibro$seurat_clusters == 3 ~ "Endothelial", 
                         fibro$seurat_clusters == 4 ~ "apCAF")
Idents(fibro) <- "label"
p26 <- DimPlot(fibro, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p26

Here’s the marker genes for each cluster.

DefaultAssay(fibro) <- "SCT"
fibro_markers2 <- FindAllMarkers(fibro, 
                                 logfc.threshold = 2, 
                                 test.use = "wilcox", 
                                 only.pos = TRUE, 
                                 random.seed = 629, 
                                 verbose = FALSE) %>% 
                  filter(p_val_adj < .05) %>% 
                  mutate(source = "Stroma", 
                         log2fc_cutoff = 2)
top5_fibro_markers <- fibro_markers2 %>% 
                      group_by(cluster) %>% 
                      arrange(desc(avg_log2FC)) %>% 
                      slice_head(n = 5)
p27 <- DotPlot(fibro, features = top5_fibro_markers$gene, dot.scale = 15) + 
       scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
       labs(color = "Expression", size = "% Expressed") + 
       theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
             legend.position = "right", 
             legend.justification = "center", 
             panel.border = element_rect(fill = NA, size = 1, color = "black"), 
             axis.line = element_blank(), 
             legend.title = element_text(size = 18), 
             axis.title.x = element_blank(), 
             axis.title.y = element_blank(), 
             axis.text.y = element_text(size = 18)) + 
       guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
              size = guide_legend(title.position = "top", title.hjust = 0.5))
p27

We’ll also compute CAF-only marker genes & visualize them.

caf <- subset(fibro, subset = label %in% c("iCAF", "myCAF", "apCAF"))
caf_markers <- FindAllMarkers(caf, 
                              logfc.threshold = 2, 
                              test.use = "wilcox", 
                              only.pos = TRUE, 
                              random.seed = 629, 
                              verbose = FALSE) %>% 
               filter(p_val_adj < .05) %>% 
               mutate(source = "CAF", 
                      log2fc_cutoff = 2)
top5_caf_markers <- caf_markers %>% 
                    group_by(cluster) %>% 
                    arrange(desc(avg_log2FC)) %>% 
                    slice_head(n = 5)
p28 <- DotPlot(caf, features = top5_caf_markers$gene, dot.scale = 15) + 
       scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
       labs(color = "Expression", size = "% Expressed") + 
       theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
             legend.position = "right", 
             legend.justification = "center", 
             panel.border = element_rect(fill = NA, size = 1, color = "black"), 
             axis.line = element_blank(), 
             legend.title = element_text(size = 18), 
             axis.title.x = element_blank(), 
             axis.title.y = element_blank(), 
             axis.text.y = element_text(size = 18)) + 
       guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
              size = guide_legend(title.position = "top", title.hjust = 0.5))
p28

T Cells

Going back to the main Seurat object, we should have a large population of T and NK cells that warrants further investigation. Using CD3D expression we can easily identify clusters 0, 3, and 7 as the mixed T & NK cells. We already see some good separation, so reclustering the cells should have good results.

p29 <- FeaturePlot(pdac, reduction = "tsne", features = "CD3D", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p29 / p4

Here’s the cells we’ll be reclustering.

nkt_cells <- rownames(pdac@meta.data[pdac@meta.data$seurat_clusters %in% c(0, 3, 8), ])
p30 <- DimPlot(pdac, reduction = "tsne", cells.highlight = nkt_cells, cols.highlight = "navy", pt.size = 0.75) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend()
p30 / p4

Tumor

nkt_tumor <- subset(pdac, subset = seurat_clusters %in% c(0, 3, 8) & condition == "PDAC")

Reclustering

Here we run ReclusterCells(), while treating the NK & T cell clusters as one large group. This will hopefully allow use to elucidate T cell subtypes. We use fewer PCs for these cells since the differences between immune cells are subtle, and adding more PCs will most likely only contribute noise to our analyses.

nkt_tumor <- ReclusterCells(nkt_tumor, 
                            which.clust = list(0, 3, 8), 
                            merge.clusters = TRUE, 
                            n.HVG = 4000, 
                            n.PC = 15, 
                            k.vals = c(30, 40, 50, 60), 
                            resolution.vals = c(.1, .2, .3), 
                            redo.embedding = TRUE, 
                            random.seed = 629)
nkt_tumor_pc <- Embeddings(nkt_tumor, "pca")
## [1] "Reclustering cells in clusters 0, 3, 8 using k = 30 & resolution = 0.3; S = 0.455"

Once again we’ll run Fit-SNE on the reclustered cells.

# import data
nkt_tumor_pc = r.nkt_tumor_pc
# run Fit-SNE
affin_nkt_tumor = PerplexityBasedNN(nkt_tumor_pc, perplexity=100, metric='cosine', random_state=629)
init = initialization.pca(nkt_tumor_pc, random_state=629)
tsne_nkt_tumor = TSNEEmbedding(init, affin_nkt_tumor, negative_gradient_method='fft')
embed_nkt_tumor1 = tsne_nkt_tumor.optimize(n_iter=250, exaggeration=4, momentum=0.6) 
embed_nkt_tumor2 = embed_nkt_tumor1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
affin_nkt_tumor.set_perplexity(50)
embed_nkt_tumor3 = embed_nkt_tumor2.optimize(n_iter=500, exaggeration=1, momentum=0.6)

The reembedding isn’t perfect, which we somewhat expected as immune cells are difficult to tell apart based on the transcriptome alone.

embed_nkt_tumor <- as.matrix(py$embed_nkt_tumor3)
rownames(embed_nkt_tumor) <- colnames(nkt_tumor)
nkt_tumor@reductions$bh_tsne <- nkt_tumor@reductions$tsne
nkt_tumor@reductions$tsne<- CreateDimReducObject(embeddings = embed_nkt_tumor, 
                                                 key = "FitSNE_", 
                                                 assay = "SCT", 
                                                 global = TRUE)
p31 <- DimPlot(nkt_tumor, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::category20_d3")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p31

Cell Type Identification

CD4+ T

Clusters 0 and 1 contain our CD4+ T cells, which we characterize using IL7R as we did in the PBMC3k vignette. It’s somewhat outside of our scope here to determine which subtype each cluster belongs to, so we’ll simply assign both clusters the same label and move on.

p32 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "IL7R", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p33 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD69", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p32 | p33) / p31

T-regs

Cluster 3 contains the regulatory T cells.

p34 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "IL2RA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p35 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "FOXP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p34 | p35) / p31

Proliferating T-regs

We can find the proliferating T-regs in cluster 7.

p36 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "TOP2A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p36 / p31

Mast

Mast cells can be identified using TPSAB1 expression in cluster 6.

p37 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "TPSAB1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p37 / p31

NK

NKG7 and PRF1 show us the NK cells in cluster 5.

p38 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "NKG7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p39 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "PRF1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p38 | p39) / p31

CD8+ T

We use CD8A and CD2 to reveal the CD8+ T cells within clusters 2 and 4.

p40 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD8A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p41 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD2", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p40 | p41) / p31

Intermediate Monocyte

Lastly, we have cluster 8, which doesn’t highly express our pan-T/NK cell markers CD3D and CD2. It could be a myeloid cell cluster that was mistakenly grouped with the T/NK cells. We’ll start with a Wilcoxon test to determine its differentially expressed genes. Interestingly, several intermediate monocyte markers - LYZ, HLA-DRA, CD74, and HLA-DPB1 - are differentially expressed in cluster 8.

clust8_markers <- FindAllMarkers(nkt_tumor, 
                                 test.use = "wilcox",
                                 min.diff.pct = .2,
                                 logfc.threshold = .5, 
                                 verbose = FALSE, 
                                 random.seed = 629) %>% 
                  filter(cluster == 8, p_val_adj < .05) %>% 
                  arrange(desc(1 - p_val_adj))
clust8_markers %>% 
  filter(gene %in% c("LYZ", "HLA-DRA", "CD74", "HLA-DPB1")) %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  kbl(booktabs = TRUE, digits = 4, row.names = FALSE) %>% 
  kable_minimal("hover", full_width = FALSE)
cluster gene avg_log2FC p_val_adj pct.1 pct.2
8 HLA-DRA 3.1725 0 0.974 0.410
8 HLA-DPB1 2.2895 0 0.895 0.387
8 CD74 2.7595 0 0.974 0.723
8 LYZ 1.9255 0 0.526 0.107

We’ll plot some of those markers below.

p42 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "LYZ", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p43 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "HLA-DRA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p44 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD74", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p45 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "HLA-DPB1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
((p42 | p43) / (p44 | p45)) / p31

Visualization

We add labels to our T cell Seurat object and visualize the results.

nkt_tumor$label <- case_when(nkt_tumor$seurat_clusters == 0 ~ "CD4+ T", 
                             nkt_tumor$seurat_clusters == 1 ~ "CD4+ T", 
                             nkt_tumor$seurat_clusters == 2 ~ "CD8+ T", 
                             nkt_tumor$seurat_clusters == 3 ~ "T-reg", 
                             nkt_tumor$seurat_clusters == 4 ~ "CD8+ T", 
                             nkt_tumor$seurat_clusters == 5 ~ "NK", 
                             nkt_tumor$seurat_clusters == 6 ~ "Mast", 
                             nkt_tumor$seurat_clusters == 7 ~ "Proliferating T-reg", 
                             nkt_tumor$seurat_clusters == 8 ~ "Intermediate Monocyte")
Idents(nkt_tumor) <- "label"
p46 <- DimPlot(nkt_tumor, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p46

Here’s the marker genes.

nkt_tumor_markers2 <- FindAllMarkers(nkt_tumor, 
                                     logfc.threshold = .75, 
                                     test.use = "wilcox", 
                                     only.pos = TRUE, 
                                     random.seed = 629, 
                                     verbose = FALSE) %>% 
                      filter(p_val_adj < .05) %>% 
                      mutate(source = "NK/T Tumor", 
                             log2fc_cutoff = .75)
top5_nkt_tumor_markers <- nkt_tumor_markers2 %>% 
                          group_by(cluster) %>% 
                          arrange(desc(avg_log2FC)) %>% 
                          slice_head(n = 5)
p47 <- DotPlot(nkt_tumor, features = unique(top5_nkt_tumor_markers$gene), dot.scale = 15) + 
       scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
       labs(color = "Expression", size = "% Expressed") + 
       theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
             legend.position = "right", 
             legend.justification = "center", 
             panel.border = element_rect(fill = NA, size = 1, color = "black"), 
             axis.line = element_blank(), 
             legend.title = element_text(size = 18), 
             axis.title.x = element_blank(), 
             axis.title.y = element_blank(), 
             axis.text.y = element_text(size = 18)) + 
       guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
              size = guide_legend(title.position = "top", title.hjust = 0.5))
p47

Adjacent Normal

nkt_norm <- subset(pdac, subset = seurat_clusters %in% c(0, 3, 8) & condition == "AdjNorm")

Reclustering

nkt_norm <- ReclusterCells(nkt_norm, 
                           which.clust = list(0, 3, 8), 
                           merge.clusters = TRUE, 
                           n.HVG = 4000, 
                           n.PC = 10, 
                           k.vals = c(15, 20, 25), 
                           resolution.vals = c(.2, .3, .4), 
                           nn.metric = "euclidean", 
                           redo.embedding = TRUE, 
                           random.seed = 629)
nkt_norm_pc <- Embeddings(nkt_norm, "pca")
## [1] "Reclustering cells in clusters 0, 3, 8 using k = 15 & resolution = 0.3; S = 0.438"

As with the other reclusterings, we’ll run Fit-SNE in order to (hopefully) obtain a better low-dimensional embedding of our cells.

# import data
nkt_norm_pc = r.nkt_norm_pc
# run Fit-SNE
affin_nkt_norm = PerplexityBasedNN(nkt_norm_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(nkt_norm_pc, random_state=629)
tsne_nkt_norm = TSNEEmbedding(init, affin_nkt_norm, negative_gradient_method='fft')
embed_nkt_norm1 = tsne_nkt_norm.optimize(n_iter=250, exaggeration=12, momentum=0.6) 
embed_nkt_norm2 = embed_nkt_norm1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
embed_nkt_norm <- as.matrix(py$embed_nkt_norm2)
rownames(embed_nkt_norm) <- colnames(nkt_norm)
nkt_norm@reductions$bh_tsne <- nkt_norm@reductions$tsne
nkt_norm@reductions$tsne<- CreateDimReducObject(embeddings = embed_nkt_norm, 
                                                key = "FitSNE_", 
                                                assay = "SCT", 
                                                global = TRUE)
p48 <- DimPlot(nkt_norm, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p48

Cell Type Identification

First we’ll use a Wilcoxon test to determine which genes characterize each cluster.

nkt_norm_markers <- FindAllMarkers(nkt_norm, 
                                   logfc.threshold = .5, 
                                   min.diff.pct = .2, 
                                   verbose = FALSE, 
                                   only.pos = TRUE, 
                                   random.seed = 629) %>% 
                    filter(p_val_adj < .05)
nkt_norm_markers  %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  group_by(cluster) %>% 
  top_n(n = 3, wt = avg_log2FC) %>% 
  kbl(booktabs = TRUE, digits = 4) %>% 
  kable_minimal("hover", full_width = FALSE)
cluster gene avg_log2FC p_val_adj pct.1 pct.2
0 KLRB1 1.7367 0 0.843 0.316
0 IL7R 0.8630 0 0.897 0.612
1 GZMK 1.5317 0 0.925 0.350
1 CST7 0.9069 0 0.846 0.452
1 CCL4 1.0830 0 0.817 0.377
3 KLRC1 0.8868 0 0.429 0.050
3 GNLY 1.2618 0 0.521 0.122
3 HOPX 0.6239 0 0.663 0.297
4 GZMB 2.3387 0 0.730 0.090
4 NKG7 2.2958 0 0.873 0.515
4 GNLY 2.5414 0 0.611 0.149
5 TNFRSF4 1.7814 0 0.691 0.043
5 TNFRSF18 1.6798 0 0.660 0.047
5 LTB 1.7286 0 0.915 0.472
6 SELL 1.1920 0 0.761 0.080
6 CCR7 1.0374 0 0.705 0.107
6 EIF3E 0.7694 0 0.830 0.520
7 STMN1 2.7810 0 0.909 0.094
7 TUBA1B 3.1534 0 1.000 0.310
7 HMGB2 3.1877 0 1.000 0.424
CD4+ T

We can use IL7R and S100A4 expression to identify the memory CD4+ T cells in clusters 0 & 2. IL7R and CCR7 identify the naive CD4+ T cells in the adjacent cluster 6.

p49 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "IL7R", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p50 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "S100A4", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p51 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "CCR7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p49 | p50 | p51) / p48

CD8+ T

Next we reveal the CD8+ T cells in clusters 1 and 3 with CD8A, as per usual.

p52 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "CD8A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p52 / p48

T-reg

The T-reg cluster, cluster 5, is identified using TIGIT and FOXP3.

p53 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TIGIT", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p54 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "FOXP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p53 | p54) / p48

NK

The natural killers can be found in cluster 4 through their expression of PRF1 and NKG7. The NKG7 expression also confirms the identities of the CD8+ T cells we just annotated.

p55 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "PRF1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p56 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "NKG7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p55 | p56) / p48

Proliferating T-reg

The tiny proliferating T-reg population in cluster 7 is characterized by TOP2A.

p57 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TOP2A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p57 / p48

Visualization

We add final cell labels to our 8 cell clusters.

nkt_norm$label <- case_when(nkt_norm$seurat_clusters == 0 ~ "Memory CD4+ T", 
                            nkt_norm$seurat_clusters == 1 ~ "CD8+ T",
                            nkt_norm$seurat_clusters == 2 ~ "Memory CD4+ T",
                            nkt_norm$seurat_clusters == 3 ~ "CD8+ T",
                            nkt_norm$seurat_clusters == 4 ~ "NK",
                            nkt_norm$seurat_clusters == 5 ~ "T-reg", 
                            nkt_norm$seurat_clusters == 6 ~ "Naive CD4+ T", 
                            nkt_norm$seurat_clusters == 7 ~ "Proliferating T-reg")
Idents(nkt_norm) <- "label"
p58 <- DimPlot(nkt_norm, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p58

Here’s the marker genes.

nkt_norm_markers2 <- FindAllMarkers(nkt_norm, 
                                    logfc.threshold = .75, 
                                    test.use = "wilcox", 
                                    only.pos = TRUE, 
                                    random.seed = 629, 
                                    verbose = FALSE) %>% 
                      filter(p_val_adj < .05) %>% 
                      mutate(source = "NK/T Adjacent Normal", 
                             log2fc_cutoff = .75)
top5_nkt_norm_markers <- nkt_norm_markers2%>% 
                         group_by(cluster) %>% 
                         arrange(desc(avg_log2FC)) %>% 
                         slice_head(n = 5)
p59 <- DotPlot(nkt_norm, features = unique(top5_nkt_norm_markers$gene), dot.scale = 15) + 
       scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
       labs(color = "Expression", size = "% Expressed") + 
       theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
             legend.position = "right", 
             legend.justification = "center", 
             panel.border = element_rect(fill = NA, size = 1, color = "black"), 
             axis.line = element_blank(), 
             legend.title = element_text(size = 18), 
             axis.title.x = element_blank(), 
             axis.title.y = element_blank(), 
             axis.text.y = element_text(size = 18)) + 
       guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
              size = guide_legend(title.position = "top", title.hjust = 0.5))
p59

Ductal Cells

Reclustering

We use KRT8 expression to show the ductal cells residing in clusters 5 and 9. We note that some regions of clusters 5 and 9 have no KRT8 expression, which likely means that they are composed of different cell types.

p60 <- FeaturePlot(pdac, reduction = "tsne", features = "KRT8", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p60 / p4

These are the cells we’ll be reclustering.

ductal_cells <- rownames(pdac@meta.data[pdac@meta.data$seurat_clusters %in% c(5, 9), ])
p61 <- DimPlot(pdac, reduction = "tsne", cells.highlight = ductal_cells, cols.highlight = "navy", pt.size = 0.75) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend()
p61 / p4

We run SCISSORS, then use a Wilcoxon differential expression test to determine potential markers for each cluster.

ductal <- ReclusterCells(pdac, 
                         which.clust = list(5, 9), 
                         merge.clusters = TRUE, 
                         n.HVG = 4000, 
                         n.PC = 20, 
                         k.vals = c(20, 30, 40, 50), 
                         nn.metric = "euclidean", 
                         resolution.vals = c(.2, .3, .4), 
                         redo.embedding = TRUE, 
                         random.seed = 629)
ductal$cluster_color <- case_when(ductal$seurat_clusters == 0 ~ paletteer_d("ggsci::default_nejm")[1],
                                  ductal$seurat_clusters == 1 ~ paletteer_d("ggsci::default_nejm")[2],
                                  ductal$seurat_clusters == 2 ~ paletteer_d("ggsci::default_nejm")[3],
                                  ductal$seurat_clusters == 3 ~ paletteer_d("ggsci::default_nejm")[4],
                                  ductal$seurat_clusters == 4 ~ paletteer_d("ggsci::default_nejm")[5],
                                  ductal$seurat_clusters == 5 ~ paletteer_d("ggsci::default_nejm")[6])
ductal_markers <- FindAllMarkers(ductal, 
                                 logfc.threshold = .5, 
                                 min.diff.pct = .2, 
                                 only.pos = TRUE, 
                                 verbose = FALSE, 
                                 random.seed = 629) %>% 
                  filter(p_val_adj < .05)
ductal_markers %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  group_by(cluster) %>% 
  top_n(n = 3, wt = avg_log2FC) %>% 
  kbl(booktabs = TRUE, digits = 4) %>% 
  kable_minimal("hover", full_width = FALSE)
## [1] "Reclustering cells in clusters 5, 9 using k = 50 & resolution = 0.2; S = 0.537"
cluster gene avg_log2FC p_val_adj pct.1 pct.2
0 MUCL3 2.0586 0 0.823 0.204
0 SLPI 1.9466 0 0.976 0.698
0 PSCA 1.8493 0 0.705 0.208
1 MUC1 1.0754 0 0.874 0.581
1 PLCG2 1.5615 0 0.464 0.173
1 LYZ 1.5575 0 0.873 0.614
2 CELA3A 6.7301 0 0.796 0.053
2 CTRB1 6.5305 0 0.741 0.058
2 CTRB2 8.2024 0 0.847 0.125
3 SERPING1 3.1176 0 0.996 0.266
3 CLU 3.5991 0 1.000 0.340
3 SPP1 5.3722 0 0.992 0.416
4 S100A2 4.4199 0 0.959 0.109
4 CST1 3.6054 0 0.497 0.012
4 PLAT 3.2459 0 0.782 0.126
5 APOA4 5.4298 0 0.698 0.002
5 APOA1 5.8060 0 0.746 0.007
5 ALDOB 4.3565 0 0.968 0.043
6 CRISP3 4.3529 0 0.930 0.022
6 CRP 3.6976 0 0.789 0.050
6 TCN1 4.2364 0 0.895 0.119

Again, we’ll run Fit-SNE on the reclustered cells.

duct_pc <- Embeddings(ductal, reduction = "pca")
# import data
duct_pc = r.duct_pc
# run Fit-SNE
affin_duct = PerplexityBasedNN(duct_pc, perplexity=30, random_state=629)
init = initialization.pca(duct_pc, random_state=629)
tsne_duct = TSNEEmbedding(init, affin_duct, negative_gradient_method='fft')
embed_d1 = tsne_duct.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_d2 = embed_d1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results into R, making sure to save the Barnes-Hut t-SNE results in another reduction slot.

embed_duct <- as.matrix(py$embed_d2)
rownames(embed_duct) <- colnames(ductal)
ductal@reductions$bh_tsne <- ductal@reductions$tsne
ductal@reductions$tsne<- CreateDimReducObject(embeddings = embed_duct, 
                                              key = "FitSNE_", 
                                              assay = "SCT", 
                                              global = TRUE)
p62 <- DimPlot(ductal, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p62

We’ll also run VAM, using the Yeh Lab’s gene sets for basal and classical PDAC.

pdac_gene_sets <- list(classical_genes, basal_genes)
names(pdac_gene_sets) <- c("Classical PDAC", "Basal-like PDAC")
for (i in seq(pdac_gene_sets)) {
  pdac_gene_sets[[i]] <- pdac_gene_sets[[i]][pdac_gene_sets[[i]] %in% rownames(ductal)]
}
ductal <- vamForSeurat(ductal, 
                       gene.set.collection = pdac_gene_sets, 
                       gamma = TRUE)
DefaultAssay(ductal) <- "VAMcdf"

Examining the VAM results, we see that clusters 0 & 1 are enriched for Classical PDAC, and cluster 4 has very high Basal PDAC scores.

p63 <- FeaturePlot(ductal, reduction = "tsne", features = "Classical PDAC") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p64 <- FeaturePlot(ductal, reduction = "tsne", features = "Basal-like PDAC") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p63 | p64) / p62

Cell Type Identification

Lipid Processing

We use ANPEP & FABP1 expression to identify the lipid processing ductal cells in cluster 6.

DefaultAssay(ductal) <- "SCT"
p65 <- FeaturePlot(ductal, reduction = "tsne", features = "ANPEP", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p66 <- FeaturePlot(ductal, reduction = "tsne", features = "FABP1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p65 | p66) / p62

Secretory

Expression of SOD3 and CFTR reveals the secretory cells in cluster 3.

p67 <- FeaturePlot(ductal, reduction = "tsne", features = "SOD3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p68 <- FeaturePlot(ductal, reduction = "tsne", features = "CFTR", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p67 | p68) / p62

Classical 1

We use TFF1 and TFF2 expression to annotate the classical 1 epithelial cells in clusters 0 and 1. We can also see that the two classical 1 clusters are split by the sample from which the cells originate. Going forward, we’ll simply label both clusters as classical 1.

p69 <- FeaturePlot(ductal, reduction = "tsne", features = "TFF1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p70 <- FeaturePlot(ductal, reduction = "tsne", features = "TFF2", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p71 <- DimPlot(ductal, reduction = "tsne", group.by = "sample", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p69 | p70 | p71) / p62

Classical 2

The classical 2 cells are located in cluster 6, as evidenced by their expression of CRISP3. We also see that GATA6, a canonical classical PDAC marker, is expressed in both classical clusters, but not in the putative basal cluster.

p72 <- FeaturePlot(ductal, reduction = "tsne", features = "CRISP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p73 <- FeaturePlot(ductal, reduction = "tsne", features = "GATA6", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p72 | p73) / p62

Basal

The basal compartment weights from DECODER are highest in cluster 4, which we will denote as being composed of basal-like PDAC.

p74 <- FeaturePlot(ductal, reduction = "tsne", features = "basal", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Basal") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p75 <- FeaturePlot(ductal, reduction = "tsne", features = "classical", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Classical") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p76 <- FeaturePlot(ductal, reduction = "tsne", features = "bc_ratio", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Basal:Classical") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p77 <- FeaturePlot(ductal, reduction = "tsne", features = "malig", pt.size = 1.5) + 
       scale_color_manual(values = wes_palette("Zissou1", n = 5)[c(5, 2)])  + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Malignant") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p74 | p75 | p76 | p77) / p62

Acinar

Lastly, we show that cluster 2 is composed of acinar cells using CTRB2.

p78 <- FeaturePlot(ductal, reduction = "tsne", features = "CTRB2", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p78 / p62

Visualization

We add final cluster labels to our Seurat object and visualize the results.

ductal$label <- case_when(ductal$seurat_clusters == 0 ~ "Classical 1", 
                          ductal$seurat_clusters == 1 ~ "Classical 1", 
                          ductal$seurat_clusters == 2 ~ "Acinar", 
                          ductal$seurat_clusters == 3 ~ "Secretory", 
                          ductal$seurat_clusters == 4 ~ "Basal", 
                          ductal$seurat_clusters == 5 ~ "Lipid Proc.", 
                          ductal$seurat_clusters == 6 ~ "Classical 2")
Idents(ductal) <- "label"
p79 <- DimPlot(ductal, reduction = "tsne",pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p79

The Basal cluster, along with the Classical 2 cluster, shows a high percentage of malignant cells as identified by CONICSmat.

ductal@meta.data %>% 
  mutate(malig2 = case_when(malig == "Malignant" ~ 1, TRUE ~ 0)) %>% 
  group_by(label) %>% 
  summarise(M = mean(malig2)) %>% 
  mutate(M = formattable::percent(M, digits = 2)) %>% 
  kbl(booktabs = TRUE, col.names = c("Celltype", "Mean % Malignant")) %>% 
  kable_minimal(full_width = FALSE)
Celltype Mean % Malignant
Acinar 10.20%
Basal 76.19%
Classical 1 50.21%
Classical 2 77.19%
Lipid Proc. 4.76%
Secretory 58.53%

Here’s the marker genes.

ductal_markers2 <- FindAllMarkers(ductal, 
                                  logfc.threshold = 2, 
                                  test.use = "wilcox", 
                                  only.pos = TRUE, 
                                  random.seed = 629, 
                                  verbose = FALSE) %>% 
                   filter(p_val_adj < .05) %>% 
                   mutate(source = "Ductal", 
                          log2fc_cutoff = 2)
top5_ductal_markers <- ductal_markers2 %>% 
                       group_by(cluster) %>% 
                       arrange(desc(avg_log2FC)) %>% 
                       slice_head(n = 5)
p80 <- DotPlot(ductal, features = unique(top5_ductal_markers$gene), dot.scale = 15) + 
       scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
       labs(color = "Expression", size = "% Expressed") + 
       theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
             legend.position = "right", 
             legend.justification = "center", 
             panel.border = element_rect(fill = NA, size = 1, color = "black"), 
             axis.line = element_blank(), 
             legend.title = element_text(size = 18), 
             axis.title.x = element_blank(), 
             axis.title.y = element_blank(), 
             axis.text.y = element_text(size = 18)) + 
       guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
              size = guide_legend(title.position = "top", title.hjust = 0.5))
p80

Plasma Cells & Plasmacytoid DCs

We use JCHAIN (denoted IGJ in Elyada et al) to reveal the Plasma cells in cluster 10, and IRF7 to identify the plasmacytoid DCs in cluster 11.

p81 <- FeaturePlot(pdac, reduction = "tsne", features = "JCHAIN", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "JCHAIN (IGJ)") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p82 <- FeaturePlot(pdac, reduction = "tsne", features = "IRF7", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "IRF7") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p81 | p82) / p4

B Cells

We can identify the B cells in cluster 4 using joint expression of MS4A1 and CD79A. The cluster is split into two subclusters by tissue type: adjacent normal and PDAC. While it would be interesting to determine the genetic drivers of that separation, it’s somewhat outside of our scope here.

p83 <- FeaturePlot(pdac, reduction = "tsne", features = "MS4A1", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "MS4A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p84 <- FeaturePlot(pdac, reduction = "tsne", features = "CD79A", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD79A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p85 <- DimPlot(pdac, reduction = "tsne", group.by = "condition", pt.size = 0.75) + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Tissue Type") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p83 | p84 | p85) / p4

Myeloid Cells

Lastly, we’ll split up the myeloid population by tissue condition (PDAC vs. adjacent normal) just like we did with the NK / T cells. We’ll run SCISSORS, annotate the clusters, and visualize the results.

Here’s the cells we’ll be reclustering.

myeloid_cells <- rownames(pdac@meta.data[pdac@meta.data$seurat_clusters %in% c(1, 2, 7), ])
p86 <- DimPlot(pdac, reduction = "tsne", cells.highlight = myeloid_cells, cols.highlight = "navy", pt.size = 0.75) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend()
p86 / p4

Tumor

First we’ll attempt to assign broad cell type labels to each of the four putative myeloid clusters. We’ll use the marker genes from Elyada et al once again.

myo_tumor <- subset(pdac, subset = seurat_clusters %in% c(1, 2, 7) & condition == "PDAC")
p87 <- DimPlot(myo_tumor, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p87

Cluster 1 appears to be composed of our resident & alternatively activated macrophages due to its expression of CD14 & C1QA and SPP1, respectively.

p88 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "CD14", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD14") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p89 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "C1QA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "C1QA") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p90 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "SPP1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "SPP1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p88 | p89 | p90) / p87

We can use LYZ and S100A8 expression to reveal the classic monocytes and neutrophils in cluster 2.

p91 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "LYZ", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "LYZ") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p92 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "S100A8", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A8") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p91 | p92) / p87

Lastly, we show that cluster 6 contains our various DC subtypes through its expression of FCER1A, a canonical dendritic cell marker.

p93 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "FCER1A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "FCER1A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p93 / p87

Reclustering

We’ll start with the Macrophages & Monocytes, since the DC populations are small and are best dealt with on their own.

myo_reclust <- ReclusterCells(myo_tumor, 
                              which.clust = c(1, 2), 
                              n.PC = 15, 
                              merge.clusters = TRUE, 
                              k.vals = c(40, 50, 60), 
                              resolution.vals = c(.2, .3, .4), 
                              n.HVG = 4000, 
                              redo.embedding = TRUE, 
                              random.seed = 629)
dc_reclust <- ReclusterCells(myo_tumor, 
                             which.clust = 7, 
                             n.PC = 15, 
                             k.vals = c(20, 30, 40, 50), 
                             resolution.vals = c(.3, .4, .5), 
                             n.HVG = 4000, 
                             nn.metric = "euclidean", 
                             redo.embedding = TRUE, 
                             random.seed = 629)
## [1] "Reclustering cells in clusters 1, 2 using k = 60 & resolution = 0.2; S = 0.337"
## [1] "Reclustering cells in cluster 7 using k = 30 & resolution = 0.4; S = 0.429"

We’ll again run Fit-SNE on our reclustered cells.

mono_tumor_pc <- Embeddings(myo_reclust, "pca")
dc_tumor_pc <- Embeddings(dc_reclust, "pca")
# import data
mono_pc = r.mono_tumor_pc
dc_pc = r.dc_tumor_pc
# Fit-SNE - monocytes & macrophages
affin_mono = PerplexityBasedNN(mono_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(mono_pc, random_state=629)
tsne_mono = TSNEEmbedding(init, affin_mono, negative_gradient_method='fft')
embed_mono1 = tsne_mono.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_mono2 = embed_mono1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
# Fit-SNE - DC
affin_dc = PerplexityBasedNN(dc_pc, perplexity=30, random_state=629)
init = initialization.pca(dc_pc, random_state=629)
tsne_dc = TSNEEmbedding(init, affin_dc, negative_gradient_method='fft')
embed_dc1 = tsne_dc.optimize(n_iter=250, exaggeration=12, momentum=0.6)
embed_dc2 = embed_dc1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results back into R and visualize them.

embed_mono <- as.matrix(py$embed_mono2)
rownames(embed_mono) <- colnames(myo_reclust)
myo_reclust@reductions$bh_tsne <- myo_reclust@reductions$tsne
myo_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_mono, 
                                                   key = "FitSNE_", 
                                                   assay = "SCT",
                                                   global = TRUE)
p94 <- DimPlot(myo_reclust, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p94

embed_dc <- as.matrix(py$embed_dc2)
rownames(embed_dc) <- colnames(dc_reclust)
dc_reclust@reductions$bh_tsne <- dc_reclust@reductions$tsne
dc_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_dc, 
                                                  key = "FitSNE_", 
                                                  assay = "SCT",
                                                  global = TRUE)
p95 <- DimPlot(dc_reclust, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p95

Cell Type Identification

Monoctyes, Macrophages, & Neutrophils

First we ID the neutrophils in cluster 2 using S100A8 and S100A9 - marker genes used by Elyada et al.

p96 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "S100A8", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A8") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p97 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "S100A9", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A9") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p96 | p97) / p94

We can identify the classical monocytes in cluster 1 through their expression of CD14 and lack of expression of CD16 aka FCGR3A, expression of which, alongside that of MS4A7, reveals the group of CD16+ monocytes in cluster 4. Finally, expression of those genes as well as S100A10 allows us to defined cluster 5 as containing intermediate monocytes.

p98 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "CD14", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD14") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p99 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "FCGR3A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "FCGR3A (CD16)") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p100 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "MS4A7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "MS4A7") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p101 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "S100A10", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A10") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p98 | p99 | p100 | p101) / p94

Expression of C1QA, APOE, and SPP1 show us the resident and alternatively activated macrophages in clusters 0 and 3, respectively.

p102 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "C1QA", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "C1QA") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p103 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "APOE", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "APOE") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p104 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "SPP1", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "SPP1") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p102 | p103 | p104) / p94

We add cell labels to our Seurat object, then we’re off to the DCs.

myo_reclust$label <- case_when(myo_reclust$seurat_clusters == 0 ~ "Resident Macrophage", 
                               myo_reclust$seurat_clusters == 1 ~ "Classical Monocyte", 
                               myo_reclust$seurat_clusters == 2 ~ "Neutrophil", 
                               myo_reclust$seurat_clusters == 3 ~ "Alt. Activated Macrophage", 
                               myo_reclust$seurat_clusters == 4 ~ "CD16+ Monocyte", 
                               myo_reclust$seurat_clusters == 5 ~ "Intermediate Monocyte")
Idents(myo_reclust) <- "label"
Dendritic Cells

We can use CLEC9A to annotate the cDC1 population in cluster 5.

p105 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CLEC9A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CLEC9A") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p105 / p95

High and low expression of CD1A and CD207 reveal the Langerhans-like DCB and DCA cells in clusters 3 and 4, respectively.

p106 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CD1A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD1A") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p107 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CD207", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD207") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p106 | p107) / p95

Next we use LAMP3 to identify the activated DCs in cluster 6.

p108 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "LAMP3", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "LAMP3") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p108 / p95

Lastly, we use expression of two canonical cDC2 marker genes / transcription factors to identify clusters 0, 1, and 2 as cDC2 cells, which are split by sample ID.

p109 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CLEC10A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p110 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "KLF4", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p111 <- DimPlot(dc_reclust, reduction = "tsne", group.by = "sample", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p109 | p110 | p111) / p95

We add final subcluster cell type labels to our Seurat object, then we’re off to the adjacent normal myeloid cells.

dc_reclust$label <- case_when(dc_reclust$seurat_clusters == 0 ~ "cDC2", 
                              dc_reclust$seurat_clusters == 1 ~ "cDC2", 
                              dc_reclust$seurat_clusters == 2 ~ "cDC2", 
                              dc_reclust$seurat_clusters == 3 ~ "Langerhans-like DCB", 
                              dc_reclust$seurat_clusters == 4 ~ "Langerhans-like DCA", 
                              dc_reclust$seurat_clusters == 5 ~ "cDC1", 
                              dc_reclust$seurat_clusters == 6 ~ "Activated DC")
Idents(dc_reclust) <- "label"

Visualization

Monocytes & Neutrophils
p112 <- DimPlot(myo_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p112

Here’s the marker genes.

myo_reclust_markers2 <- FindAllMarkers(myo_reclust, 
                                       logfc.threshold = 1, 
                                       test.use = "wilcox", 
                                       only.pos = TRUE, 
                                       random.seed = 629, 
                                       verbose = FALSE) %>% 
                        filter(p_val_adj < .05) %>% 
                        mutate(source = "Myeloid Tumor", 
                               log2fc_cutoff = 1)
top5_myo_reclust_markers <- myo_reclust_markers2 %>% 
                            group_by(cluster) %>% 
                            arrange(desc(avg_log2FC)) %>% 
                            slice_head(n = 5)
p113 <- DotPlot(myo_reclust, features = unique(top5_myo_reclust_markers$gene), dot.scale = 15) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
              legend.position = "right", 
              legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 18), 
              axis.title.x = element_blank(), 
              axis.title.y = element_blank(), 
              axis.text.y = element_text(size = 18)) + 
        guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p113

DCs
p114 <- DimPlot(dc_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p114

Here’s the marker genes.

dc_reclust_markers2 <- FindAllMarkers(dc_reclust, 
                                      logfc.threshold = 1, 
                                      test.use = "wilcox", 
                                      only.pos = TRUE, 
                                      random.seed = 629, 
                                      verbose = FALSE) %>% 
                       filter(p_val_adj < .05) %>% 
                       mutate(source = "DC Tumor", 
                              log2fc_cutoff = 1)
top5_dc_reclust_markers <- dc_reclust_markers2 %>% 
                           group_by(cluster) %>% 
                           arrange(desc(avg_log2FC)) %>% 
                           slice_head(n = 5)
p115 <- DotPlot(dc_reclust, features = unique(top5_dc_reclust_markers$gene), dot.scale = 15) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
              legend.position = "right", 
              legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 18), 
              axis.title.x = element_blank(), 
              axis.title.y = element_blank(), 
              axis.text.y = element_text(size = 18)) + 
        guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p115

Adjacent Normal

We have the same four clusters as in the tumor tissue - 1, 2, & 7 - and we’ll run the same analysis steps.

myo_norm <- subset(pdac, subset = seurat_clusters %in% c(1, 2, 7) & condition == "AdjNorm")

Reclustering

myo_norm_reclust <- ReclusterCells(myo_norm, 
                                   which.clust = c(1, 2), 
                                   n.PC = 15, 
                                   merge.clusters = TRUE, 
                                   k.vals = c(20, 30, 40), 
                                   resolution.vals = c(.1, .2), 
                                   n.HVG = 4000, 
                                   redo.embedding = TRUE, 
                                   random.seed = 629)
dc_norm_reclust <- ReclusterCells(myo_norm, 
                                  which.clust = 7, 
                                  n.PC = 15, 
                                  k.vals = c(20, 30, 40, 50), 
                                  resolution.vals = c(.3, .4, .5), 
                                  n.HVG = 4000, 
                                  nn.metric = "euclidean", 
                                  redo.embedding = TRUE, 
                                  random.seed = 629)
## [1] "Reclustering cells in clusters 1, 2 using k = 20 & resolution = 0.2; S = 0.328"
## [1] "Reclustering cells in cluster 7 using k = 30 & resolution = 0.3; S = 0.445"

For the last time, we run Fit-SNE in order to obtain a better embedding.

mono_norm_pc <- Embeddings(myo_norm_reclust, "pca")
dc_norm_pc <- Embeddings(dc_norm_reclust, "pca")
# import data
mono_pc = r.mono_norm_pc
dc_pc = r.dc_norm_pc
# Fit-SNE - monocytes
affin_mono = PerplexityBasedNN(mono_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(mono_pc, random_state=629)
tsne_mono = TSNEEmbedding(init, affin_mono, negative_gradient_method='fft')
embed_mono1 = tsne_mono.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_mono2 = embed_mono1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
# Fit-SNE - DC
affin_dc = PerplexityBasedNN(dc_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(dc_pc, random_state=629)
tsne_dc = TSNEEmbedding(init, affin_dc, negative_gradient_method='fft')
embed_dc1 = tsne_dc.optimize(n_iter=250, exaggeration=8, momentum=0.6)
embed_dc2 = embed_dc1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results back into R and visualize them.

embed_mono <- as.matrix(py$embed_mono2)
rownames(embed_mono) <- colnames(myo_norm_reclust)
myo_norm_reclust@reductions$bh_tsne <- myo_norm_reclust@reductions$tsne
myo_norm_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_mono, 
                                                        key = "FitSNE_", 
                                                        assay = "SCT",
                                                        global = TRUE)
p116 <- DimPlot(myo_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p116

embed_dc <- as.matrix(py$embed_dc2)
rownames(embed_dc) <- colnames(dc_norm_reclust)
dc_norm_reclust@reductions$bh_tsne <- dc_norm_reclust@reductions$tsne
dc_norm_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_dc, 
                                                       key = "FitSNE_", 
                                                       assay = "SCT",
                                                       global = TRUE)
p117 <- DimPlot(dc_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p117

Cell Type Identification

Monocytes, Macrophages, & Neutrophils

We use high S100A8 and S100A9 expression to define the neutrophils in cluster 4.

p118 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "S100A8", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p119 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "S100A9", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p118 | p119) / p116

Next up are the classical monocytes in clusters 0 and 3, split by sample.

p120 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "LYZ", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p121 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "CD14", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p122 <- DimPlot(myo_norm_reclust, reduction = "tsne", group.by = "sample", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p120 | p121 | p122) / p116

C1QA and APOE show us the resident macrophages in clusters 1 and 2.

p123 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "C1QA", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p124 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "APOE", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p123 | p124) / p116

Lastly, it seems we have a small group of CD8+ T cells in cluster 5 that snuck into the myeloid cluster, as defined by their expression of CD3D (marking them as NK / T cells), and CD8A & NKG7. I don’t believe they’re NK cells as they do not express PRF1 or GZMB.

p125 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "CD3D") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p126 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "CD8A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p127 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "NKG7") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p125 | p126 | p127) / p116

We add labels to our clusters.

myo_norm_reclust$label <- case_when(myo_norm_reclust$seurat_clusters == 0 ~ "Classical Monocyte", 
                                    myo_norm_reclust$seurat_clusters == 1 ~ "Resident Macrophage", 
                                    myo_norm_reclust$seurat_clusters == 2 ~ "Resident Macrophage", 
                                    myo_norm_reclust$seurat_clusters == 3 ~ "Classical Monocyte", 
                                    myo_norm_reclust$seurat_clusters == 4 ~ "Neutrophil",
                                    myo_norm_reclust$seurat_clusters == 5 ~ "CD8+ T")
Idents(myo_norm_reclust) <- "label"
Dendritic Cells

We annotate cluster 1 as conventional DC1 and cluster 0 as conventional DC2 through mutually exclusive expression of the canonical markers CLEC9A and CLEC10A, respectively.

p128 <- FeaturePlot(dc_norm_reclust, reduction = "tsne", features = "CLEC9A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p129 <- FeaturePlot(dc_norm_reclust, reduction = "tsne", features = "CLEC10A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p128 | p129) / p117

Labels are added to our adjacent normal tissue DC Seurat object.

dc_norm_reclust$label <- case_when(dc_norm_reclust$seurat_clusters == 0 ~ "cDC2", 
                                   dc_norm_reclust$seurat_clusters == 1 ~ "cDC2", 
                                   dc_norm_reclust$seurat_clusters == 2 ~ "cDC1")
Idents(dc_norm_reclust) <- "label"

Visualization

Monocytes, Macrophages, & Neutrophils

Here are the final annotations for the adjacent normal tissue myeloid population.

p130 <- DimPlot(myo_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p130

And here’s their marker genes.

myo_norm_reclust_markers2 <- FindAllMarkers(myo_norm_reclust, 
                                            logfc.threshold = 1, 
                                            test.use = "wilcox", 
                                            only.pos = TRUE, 
                                            random.seed = 629, 
                                            verbose = FALSE) %>% 
                             filter(p_val_adj < .05) %>% 
                             mutate(source = "Myeloid Adjacent Normal", 
                                    log2fc_cutoff = 1)
top5_myo_norm_reclust_markers <- myo_norm_reclust_markers2 %>% 
                                 group_by(cluster) %>% 
                                 arrange(desc(avg_log2FC)) %>% 
                                 slice_head(n = 5)
p131 <- DotPlot(myo_norm_reclust, features = unique(top5_myo_norm_reclust_markers$gene), dot.scale = 15) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
              legend.position = "right", 
              legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 18), 
              axis.title.x = element_blank(), 
              axis.title.y = element_blank(), 
              axis.text.y = element_text(size = 18)) + 
        guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p131

Dendritic Cells

Here’s the final DC annotations.

p132 <- DimPlot(dc_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p132

And here are their marker genes.

dc_norm_reclust_markers2 <- FindAllMarkers(dc_norm_reclust, 
                                           logfc.threshold = 1, 
                                           test.use = "wilcox", 
                                           only.pos = TRUE, 
                                           random.seed = 629, 
                                           verbose = FALSE) %>% 
                            filter(p_val_adj < .05) %>% 
                            mutate(source = "DC Adjacent Normal", 
                                   log2fc_cutoff = 1)
top5_dc_norm_reclust_markers <- dc_norm_reclust_markers2 %>% 
                                group_by(cluster) %>% 
                                arrange(desc(avg_log2FC)) %>% 
                                slice_head(n = 5)
p133 <- DotPlot(dc_norm_reclust, features = unique(top5_dc_norm_reclust_markers$gene), dot.scale = 15) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 16, vjust = 0.5), 
              legend.position = "right", 
              legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 18), 
              axis.title.x = element_blank(), 
              axis.title.y = element_blank(), 
              axis.text.y = element_text(size = 18)) + 
        guides(color = guide_colorbar(title.position = "top", barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p133

Conclusions

SCISSORS was able to, with the help of several other methods, identify many celltypes, including celltypes that were not discovered in the original analysis done by Elyada et al. It also did so in a reproducible way, which is paramount in the era of computational biology. We believe this analysis shows the promise of SCISSORS as a valuable piece of the scRNA-seq data exploration and annotation processes.

Save Data & Figures

First we’ll save the final PDAC object.

saveRDS(pdac, "~/Desktop/Data/Elyada.Rds")
saveRDS(nkt_tumor, "~/Desktop/Data/Elyada_nkt_tumor.Rds")
saveRDS(nkt_norm, "~/Desktop/Data/Elyada_nkt_adjNorm.Rds")
saveRDS(fibro, "~/Desktop/Data/Elyada_fibro.Rds")
saveRDS(ductal, "~/Desktop/Data/Elyada_ductal.Rds")
saveRDS(myo_reclust, "~/Desktop/Data/Elyada_myeloid_tumor.Rds")
saveRDS(myo_norm_reclust, "~/Desktop/Data/Elyada_myeloid_adjNorm.Rds")
saveRDS(dc_reclust, "~/Desktop/Data/Elyada_DC_tumor.Rds")
saveRDS(dc_norm_reclust, "~/Desktop/Data/Elyada_DC_adjNorm.Rds")

Next we’ll create a final table of all the differentially expressed genes from the SCISSORS results for each celltype, and save them into one large Excel document.

caf_markers %>% 
  bind_rows(nkt_tumor_markers2) %>% 
  bind_rows(nkt_norm_markers2) %>% 
  bind_rows(ductal_markers2) %>% 
  bind_rows(myo_reclust_markers2) %>% 
  bind_rows(dc_reclust_markers2) %>% 
  bind_rows(myo_norm_reclust_markers2) %>% 
  bind_rows(dc_norm_reclust_markers2) -> SCISSORS_de_results
openxlsx::write.xlsx(SCISSORS_de_results, file = "./Data/Elyada_SCISSORS_Marker_Genes.xlsx")

We’ll create a quick convenience function to help us save the figures.

SaveFigure <- function(my.plot = NULL, name = NULL, height = 8, width = 8) {
  if (is.null(plot) | is.null(name)) stop("You forgot some arguments.")
  # save figure as is - w/ axis labels, titles, etc. 
  dir <- "~/Desktop/R/SCISSORS/vignettes/figures_supp/Elyada"
  ggsave(my.plot, 
         filename = paste0(name, ".pdf"), 
         device = "pdf", 
         units = "in",
         path = dir, 
         height = height, 
         width = width) 
  # save "blank" figure w/ no labels, legends, etc.
  dir <- "~/Desktop/R/SCISSORS/vignettes/figures_pub/Elyada"
  plot_blank <- my.plot + 
                theme(axis.title = element_blank(), 
                      panel.border = element_blank(), 
                      plot.title = element_blank(), 
                      plot.subtitle = element_blank(), 
                      plot.caption = element_blank(), 
                      legend.position = "none")
  ggsave(plot_blank, 
         filename = paste0(name, ".pdf"), 
         device = "pdf", 
         units = "in",
         path = dir, 
         height = height, 
         width = width) 
}

This section isn’t worth reading; it’s here solely to prove that the figures we present in our publication were dynamically generated during the knitting of this document.

SaveFigure(my.plot = p0, name = "Seurat_Clusters_tSNE")
SaveFigure(my.plot = p1, name = "Seurat_Clusters_Silhouette_Scores")
SaveFigure(my.plot = p2, name = "Seurat_Clusters_Dotplot", height = 8, width = 18)
SaveFigure(my.plot = p3, name = "Seurat_Clusters_UMAP")
SaveFigure(my.plot = p4, name = "Seurat_Clusters_FitSNE")
SaveFigure(my.plot = p5, name = "SingleR_scRNA_Annos_FitSNE")
SaveFigure(my.plot = p6, name = "SingleR_bulkRNA_Annos_FitSNE")
SaveFigure(my.plot = p7, name = "CONICSmat_Annos_FitSNE")
SaveFigure(my.plot = p8, name = "DECODER_Basal_PDAC_FitSNE")
SaveFigure(my.plot = p9, name = "DECODER_Classical_PDAC_FitSNE")
SaveFigure(my.plot = p10, name = "DECODER_Exocrine_FitSNE")
SaveFigure(my.plot = p11, name = "DECODER_Endocrine_FitSNE")
SaveFigure(my.plot = p12, name = "DECODER_Immune_FitSNE")
SaveFigure(my.plot = p13, name = "DECODER_Normal_Stroma_FitSNE")
SaveFigure(my.plot = p14, name = "DECODER_Activated_Stroma_FitSNE")
SaveFigure(my.plot = p15, name = "All_Cells_Stroma_COL1A1_FitSNE")
SaveFigure(my.plot = p16, name = "All_Cells_Stroma_COL3A1_FitSNE")
SaveFigure(my.plot = p17, name = "All_Cells_Stroma_LUM_FitSNE")
SaveFigure(my.plot = p18, name = "All_Cells_Stroma_DCN_FitSNE")
SaveFigure(my.plot = p19, name = "All_Cells_Highlight_Stroma_FitSNE")
SaveFigure(my.plot = p20, name = "SCISSORS_Clusters_Stroma_FitSNE")
SaveFigure(my.plot = p21, name = "SCISSORS_Clusters_Stroma_Endothelial_PLVAP")
SaveFigure(my.plot = p22, name = "SCISSORS_Clusters_Stroma_Perivascular_RGS5")
SaveFigure(my.plot = p23, name = "SCISSORS_Clusters_Stroma_VAM_iCAF")
SaveFigure(my.plot = p24, name = "SCISSORS_Clusters_Stroma_VAM_myCAF")
SaveFigure(my.plot = p25, name = "SCISSORS_Clusters_Stroma_VAM_apCAF")
SaveFigure(my.plot = p26, name = "SCISSORS_Clusters_Stroma_Labels_FitSNE")
SaveFigure(my.plot = p27, name = "SCISSORS_Clusters_Stroma_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p28, name = "SCISSORS_Clusters_CAF_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p29, name = "All_Cells_NKT_CD3D_FitSNE")
SaveFigure(my.plot = p30, name = "All_Cells_Highlight_NKT_FitSNE")
SaveFigure(my.plot = p31, name = "SCISSORS_Clusters_NKT_Tumor_FitSNE")
SaveFigure(my.plot = p32, name = "SCISSORS_Clusters_NKT_Tumor_CD4T_IL7R")
SaveFigure(my.plot = p33, name = "SCISSORS_Clusters_NKT_Tumor_CD4T_CD69")
SaveFigure(my.plot = p34, name = "SCISSORS_Clusters_NKT_Tumor_Treg_IL2RA")
SaveFigure(my.plot = p35, name = "SCISSORS_Clusters_NKT_Tumor_Treg_FOXP3")
SaveFigure(my.plot = p36, name = "SCISSORS_Clusters_NKT_Tumor_Prolif_Treg_TOP2A")
SaveFigure(my.plot = p37, name = "SCISSORS_Clusters_NKT_Tumor_Mast_TPSAB1")
SaveFigure(my.plot = p38, name = "SCISSORS_Clusters_NKT_Tumor_NK_NKG7")
SaveFigure(my.plot = p39, name = "SCISSORS_Clusters_NKT_Tumor_NK_PRF1")
SaveFigure(my.plot = p40, name = "SCISSORS_Clusters_NKT_Tumor_CD8T_CD8A")
SaveFigure(my.plot = p41, name = "SCISSORS_Clusters_NKT_Tumor_CD8T_CD2")
SaveFigure(my.plot = p42, name = "SCISSORS_Clusters_NKT_Tumor_Intermediate_Mono_LYZ")
SaveFigure(my.plot = p43, name = "SCISSORS_Clusters_NKT_Tumor_Intermediate_Mono_HLADRA")
SaveFigure(my.plot = p44, name = "SCISSORS_Clusters_NKT_Tumor_Intermediate_Mono_CD74")
SaveFigure(my.plot = p45, name = "SCISSORS_Clusters_NKT_Tumor_Intermediate_Mono_HLADPB1")
SaveFigure(my.plot = p46, name = "SCISSORS_Clusters_NKT_Tumor_Labels_FitSNE")
SaveFigure(my.plot = p47, name = "SCISSORS_Clusters_NKT_Tumor_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p48, name = "SCISSORS_Clusters_NKT_AdjNorm_FitSNE")
SaveFigure(my.plot = p49, name = "SCISSORS_Clusters_NKT_AdjNorm_CD4T_IL7R")
SaveFigure(my.plot = p50, name = "SCISSORS_Clusters_NKT_AdjNorm_CD4T_Memory_S100A4")
SaveFigure(my.plot = p51, name = "SCISSORS_Clusters_NKT_AdjNorm_CD4T_Naive_CCR7")
SaveFigure(my.plot = p52, name = "SCISSORS_Clusters_NKT_AdjNorm_CD8T_CD8A")
SaveFigure(my.plot = p53, name = "SCISSORS_Clusters_NKT_AdjNorm_Treg_TIGIT")
SaveFigure(my.plot = p54, name = "SCISSORS_Clusters_NKT_AdjNorm_Treg_FOXP3")
SaveFigure(my.plot = p55, name = "SCISSORS_Clusters_NKT_AdjNorm_NK_PRF1")
SaveFigure(my.plot = p56, name = "SCISSORS_Clusters_NKT_AdjNorm_NK_NKG7")
SaveFigure(my.plot = p57, name = "SCISSORS_Clusters_NKT_AdjNorm_Prolif_Treg_TOP2A")
SaveFigure(my.plot = p58, name = "SCISSORS_Clusters_NKT_AdjNorm_Labels_FitSNE")
SaveFigure(my.plot = p59, name = "SCISSORS_Clusters_NKT_AdjNorm_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p60, name = "All_Cells_Ductal_KRT8_FitSNE")
SaveFigure(my.plot = p61, name = "All_Cells_Highlight_Ductal_FitSNE")
SaveFigure(my.plot = p62, name = "SCISSORS_Clusters_Ductal_FitSNE")
SaveFigure(my.plot = p63, name = "SCISSORS_Clusters_Ductal_VAM_Classical25_FitSNE")
SaveFigure(my.plot = p64, name = "SCISSORS_Clusters_Ductal_VAM_Basal25_FitSNE")
SaveFigure(my.plot = p65, name = "SCISSORS_Clusters_Ductal_Lipid_Proc_ANPEP")
SaveFigure(my.plot = p66, name = "SCISSORS_Clusters_Ductal_Lipid_Proc_FABP1")
SaveFigure(my.plot = p67, name = "SCISSORS_Clusters_Ductal_Secretory_SOD3")
SaveFigure(my.plot = p68, name = "SCISSORS_Clusters_Ductal_Secretory_CFTR")
SaveFigure(my.plot = p69, name = "SCISSORS_Clusters_Ductal_Classical1_TFF1")
SaveFigure(my.plot = p70, name = "SCISSORS_Clusters_Ductal_Classical1_TFF2")
SaveFigure(my.plot = p71, name = "SCISSORS_Clusters_Ductal_SampleID")
SaveFigure(my.plot = p72, name = "SCISSORS_Clusters_Ductal_Classical2_CRISP3")
SaveFigure(my.plot = p73, name = "SCISSORS_Clusters_Ductal_Classical2_GATA6")
SaveFigure(my.plot = p74, name = "SCISSORS_Clusters_Ductal_DECODER_Basal_PDAC_FitSNE")
SaveFigure(my.plot = p75, name = "SCISSORS_Clusters_Ductal_DECODER_Classical_PDAC_FitSNE")
SaveFigure(my.plot = p76, name = "SCISSORS_Clusters_Ductal_DECODER_BC_Ratio_FitSNE")
SaveFigure(my.plot = p77, name = "SCISSORS_Clusters_Ductal_CONICSmat_Annos_FitSNE")
SaveFigure(my.plot = p78, name = "SCISSORS_Clusters_Ductal_Acinar_CTRB2")
SaveFigure(my.plot = p79, name = "SCISSORS_Clusters_Ductal_Labels_FitSNE")
SaveFigure(my.plot = p80, name = "SCISSORS_Clusters_Ductal_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p81, name = "All_Cells_Plasma_JCHAIN_FitSNE")
SaveFigure(my.plot = p82, name = "All_Cells_Plasmacytoid_DC_IRF7_FitSNE")
SaveFigure(my.plot = p83, name = "All_Cells_B_MS4A1_FitSNE")
SaveFigure(my.plot = p84, name = "All_Cells_B_CD79A_FitSNE")
SaveFigure(my.plot = p85, name = "All_Cells_Tissue_Type_FitSNE")
SaveFigure(my.plot = p86, name = "All_Cells_Highlight_Myeloid_FitSNE")
SaveFigure(my.plot = p87, name = "All_Cells_Myeloid_Tumor_Subset_FitSNE")
SaveFigure(my.plot = p88, name = "All_Cells_Myeloid_Tumor_Subset_CD14_FitSNE")
SaveFigure(my.plot = p89, name = "All_Cells_Myeloid_Tumor_Subset_C1QA_FitSNE")
SaveFigure(my.plot = p90, name = "All_Cells_Myeloid_Tumor_Subset_SPP1_FitSNE")
SaveFigure(my.plot = p91, name = "All_Cells_Myeloid_Tumor_Subset_LYZ_FitSNE")
SaveFigure(my.plot = p92, name = "All_Cells_Myeloid_Tumor_Subset_S100A8_FitSNE")
SaveFigure(my.plot = p93, name = "All_Cells_Myeloid_Tumor_Subset_FCER1A_FitSNE")
SaveFigure(my.plot = p94, name = "SCISSORS_Clusters_Myeloid_Tumor_FitSNE")
SaveFigure(my.plot = p95, name = "SCISSORS_Clusters_DC_Tumor_FitSNE")
SaveFigure(my.plot = p96, name = "SCISSORS_Clusters_Myeloid_Tumor_Neutrophil_S100A8_FitSNE")
SaveFigure(my.plot = p97, name = "SCISSORS_Clusters_Myeloid_Tumor_Neutrophil_S100A9_FitSNE")
SaveFigure(my.plot = p98, name = "SCISSORS_Clusters_Myeloid_Tumor_Classical_Mono_CD14_FitSNE")
SaveFigure(my.plot = p99, name = "SCISSORS_Clusters_Myeloid_Tumor_CD16_Mono_FCGR3A_FitSNE")
SaveFigure(my.plot = p100, name = "SCISSORS_Clusters_Myeloid_Tumor_CD16_Mono_MS4A7_FitSNE")
SaveFigure(my.plot = p101, name = "SCISSORS_Clusters_Myeloid_Tumor_Intermediate_Mono_MS4A7_FitSNE")
SaveFigure(my.plot = p102, name = "SCISSORS_Clusters_Myeloid_Tumor_Resident_Macro_C1QA_FitSNE")
SaveFigure(my.plot = p103, name = "SCISSORS_Clusters_Myeloid_Tumor_Alt_Active_Macro_APOE_FitSNE")
SaveFigure(my.plot = p104, name = "SCISSORS_Clusters_Myeloid_Tumor_Alt_Active_Macro_SPP1_FitSNE")
SaveFigure(my.plot = p105, name = "SCISSORS_Clusters_DC_Tumor_cDC1_CLEC9A_FitSNE")
SaveFigure(my.plot = p106, name = "SCISSORS_Clusters_DC_Tumor_Langerhans_DC_CD1A_FitSNE")
SaveFigure(my.plot = p107, name = "SCISSORS_Clusters_DC_Tumor_Langerhans_DC_CD207_FitSNE")
SaveFigure(my.plot = p108, name = "SCISSORS_Clusters_DC_Tumor_Active_DC_LAMP3_FitSNE")
SaveFigure(my.plot = p109, name = "SCISSORS_Clusters_DC_Tumor_cDC2_CLEC10A_FitSNE")
SaveFigure(my.plot = p110, name = "SCISSORS_Clusters_DC_Tumor_cDC2_KLF4_FitSNE")
SaveFigure(my.plot = p111, name = "SCISSORS_Clusters_DC_Tumor_SampleID_FitSNE")
SaveFigure(my.plot = p112, name = "SCISSORS_Clusters_Myeloid_Tumor_Labels_FitSNE")
SaveFigure(my.plot = p113, name = "SCISSORS_Clusters_Myeloid_Tumor_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p114, name = "SCISSORS_Clusters_DC_Tumor_Labels_FitSNE")
SaveFigure(my.plot = p115, name = "SCISSORS_Clusters_DC_Tumor_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p116, name = "SCISSORS_Clusters_Myeloid_AdjNorm_FitSNE")
SaveFigure(my.plot = p117, name = "SCISSORS_Clusters_DC_AdjNorm_FitSNE")
SaveFigure(my.plot = p118, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Neutrophil_S100A8_FitSNE")
SaveFigure(my.plot = p119, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Neutrophil_S100A9_FitSNE")
SaveFigure(my.plot = p120, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Classical_Mono_LYZ_FitSNE")
SaveFigure(my.plot = p121, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Classical_Mono_DC14_FitSNE")
SaveFigure(my.plot = p122, name = "SCISSORS_Clusters_Myeloid_AdjNorm_SampleID_FitSNE")
SaveFigure(my.plot = p123, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Resident_Macro_C1QA_FitSNE")
SaveFigure(my.plot = p124, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Resident_Macro_APOE_FitSNE")
SaveFigure(my.plot = p125, name = "SCISSORS_Clusters_Myeloid_AdjNorm_CD8T_CD3D_FitSNE")
SaveFigure(my.plot = p126, name = "SCISSORS_Clusters_Myeloid_AdjNorm_CD8T_CD8A_FitSNE")
SaveFigure(my.plot = p127, name = "SCISSORS_Clusters_Myeloid_AdjNorm_CD8T_NKG7_FitSNE")
SaveFigure(my.plot = p128, name = "SCISSORS_Clusters_DC_AdjNorm_cDC1_CLEC9A_FitSNE")
SaveFigure(my.plot = p129, name = "SCISSORS_Clusters_DC_AdjNorm_cDC2_CLEC10A_FitSNE")
SaveFigure(my.plot = p130, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Labels_FitSNE")
SaveFigure(my.plot = p131, name = "SCISSORS_Clusters_Myeloid_AdjNorm_Dotplot", height = 6, width = 12)
SaveFigure(my.plot = p132, name = "SCISSORS_Clusters_DC_AdjNorm_Labels_FitSNE")
SaveFigure(my.plot = p133, name = "SCISSORS_Clusters_DC_AdjNorm_Dotplot", height = 6, width = 12)

And of course:

sessionInfo()
## R version 4.0.4 (2021-02-15)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur 10.16
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] celldex_1.0.0               wesanderson_0.3.6          
##  [3] kableExtra_1.3.4            reticulate_1.18            
##  [5] CONICSmat_0.0.0.1           paletteer_1.3.0            
##  [7] latex2exp_0.5.0             patchwork_1.1.1            
##  [9] mixtools_1.2.0              SCISSORS_0.0.2.0           
## [11] SingleCellExperiment_1.12.0 data.table_1.14.0          
## [13] cluster_2.1.1               biomaRt_2.46.3             
## [15] decoderr_0.0.0.9000         janitor_2.1.0              
## [17] SingleR_1.4.1               SummarizedExperiment_1.20.0
## [19] Biobase_2.50.0              GenomicRanges_1.42.0       
## [21] GenomeInfoDb_1.26.7         IRanges_2.24.1             
## [23] S4Vectors_0.28.1            BiocGenerics_0.36.0        
## [25] MatrixGenerics_1.2.1        matrixStats_0.58.0         
## [27] ggplot2_3.3.3               SeuratObject_4.0.0         
## [29] Seurat_4.0.1                dplyr_1.0.5                
## [31] VAM_0.5.2                   Matrix_1.3-2               
## [33] MASS_7.3-53.1              
## 
## loaded via a namespace (and not attached):
##   [1] utf8_1.2.1                    tidyselect_1.1.0             
##   [3] RSQLite_2.2.6                 AnnotationDbi_1.52.0         
##   [5] htmlwidgets_1.5.3             grid_4.0.4                   
##   [7] BiocParallel_1.24.1           Rtsne_0.15                   
##   [9] munsell_0.5.0                 codetools_0.2-18             
##  [11] ica_1.0-2                     statmod_1.4.35               
##  [13] scran_1.18.6                  future_1.21.0                
##  [15] miniUI_0.1.1.1                withr_2.4.2                  
##  [17] colorspace_2.0-0              highr_0.8                    
##  [19] knitr_1.32                    rstudioapi_0.13              
##  [21] ROCR_1.0-11                   tensor_1.5                   
##  [23] listenv_0.8.0                 labeling_0.4.2               
##  [25] GenomeInfoDbData_1.2.4        polyclip_1.10-0              
##  [27] pheatmap_1.0.12               farver_2.1.0                 
##  [29] bit64_4.0.5                   parallelly_1.24.0            
##  [31] vctrs_0.3.7                   generics_0.1.0               
##  [33] xfun_0.22                     BiocFileCache_1.14.0         
##  [35] squash_1.0.9                  R6_2.5.0                     
##  [37] phateR_1.0.7                  rsvd_1.0.3                   
##  [39] locfit_1.5-9.4                bitops_1.0-6                 
##  [41] spatstat.utils_2.1-0          cachem_1.0.4                 
##  [43] DelayedArray_0.16.3           assertthat_0.2.1             
##  [45] promises_1.2.0.1              scales_1.1.1                 
##  [47] gtable_0.3.0                  beachmat_2.6.4               
##  [49] globals_0.14.0                goftest_1.2-2                
##  [51] rlang_0.4.10                  systemfonts_1.0.1            
##  [53] splines_4.0.4                 lazyeval_0.2.2               
##  [55] formattable_0.2.1             prismatic_1.0.0              
##  [57] spatstat.geom_2.1-0           BiocManager_1.30.12          
##  [59] yaml_2.2.1                    reshape2_1.4.4               
##  [61] abind_1.4-5                   httpuv_1.5.5                 
##  [63] tools_4.0.4                   ellipsis_0.3.1               
##  [65] spatstat.core_2.0-0           jquerylib_0.1.3              
##  [67] RColorBrewer_1.1-2            ggridges_0.5.3               
##  [69] Rcpp_1.0.6                    plyr_1.8.6                   
##  [71] sparseMatrixStats_1.2.1       progress_1.2.2               
##  [73] zlibbioc_1.36.0               purrr_0.3.4                  
##  [75] RCurl_1.98-1.3                prettyunits_1.1.1            
##  [77] rpart_4.1-15                  openssl_1.4.3                
##  [79] deldir_0.2-10                 pbapply_1.4-3                
##  [81] cowplot_1.1.1                 zoo_1.8-9                    
##  [83] ggrepel_0.9.1                 magrittr_2.0.1               
##  [85] RSpectra_0.16-0               scattermore_0.7              
##  [87] lmtest_0.9-38                 RANN_2.6.1                   
##  [89] fitdistrplus_1.1-3            hms_1.0.0                    
##  [91] mime_0.10                     evaluate_0.14                
##  [93] xtable_1.8-4                  XML_3.99-0.6                 
##  [95] gridExtra_2.3                 compiler_4.0.4               
##  [97] tibble_3.1.1                  KernSmooth_2.23-18           
##  [99] crayon_1.4.1                  htmltools_0.5.1.1            
## [101] segmented_1.3-3               mgcv_1.8-34                  
## [103] later_1.1.0.1                 tidyr_1.1.3                  
## [105] lubridate_1.7.10              DBI_1.1.1                    
## [107] ExperimentHub_1.16.0          dbplyr_2.1.1                 
## [109] rappdirs_0.3.3                igraph_1.2.6                 
## [111] pkgconfig_2.0.3               scuttle_1.0.4                
## [113] plotly_4.9.3                  spatstat.sparse_2.0-0        
## [115] xml2_1.3.2                    svglite_2.0.0                
## [117] bslib_0.2.4                   dqrng_0.2.1                  
## [119] webshot_0.5.2                 XVector_0.30.0               
## [121] rvest_1.0.0                   snakecase_0.11.0             
## [123] stringr_1.4.0                 digest_0.6.27                
## [125] sctransform_0.3.2             RcppAnnoy_0.0.18             
## [127] spatstat.data_2.1-0           rmarkdown_2.7                
## [129] leiden_0.3.7                  edgeR_3.32.1                 
## [131] uwot_0.1.10                   DelayedMatrixStats_1.12.3    
## [133] curl_4.3                      kernlab_0.9-29               
## [135] shiny_1.6.0                   lifecycle_1.0.0              
## [137] nlme_3.1-152                  jsonlite_1.7.2               
## [139] BiocNeighbors_1.8.2           limma_3.46.0                 
## [141] viridisLite_0.4.0             askpass_1.1                  
## [143] fansi_0.4.2                   pillar_1.6.0                 
## [145] lattice_0.20-41               fastmap_1.1.0                
## [147] httr_1.4.2                    survival_3.2-10              
## [149] interactiveDisplayBase_1.28.0 glue_1.4.2                   
## [151] png_0.1-7                     BiocVersion_3.12.0           
## [153] bluster_1.0.0                 bit_4.0.4                    
## [155] nnls_1.4                      stringi_1.5.3                
## [157] sass_0.3.1                    rematch2_2.1.2               
## [159] blob_1.2.1                    AnnotationHub_2.22.0         
## [161] BiocSingular_1.6.0            memoise_2.0.0                
## [163] irlba_2.3.3                   future.apply_1.7.0
LS0tCnRpdGxlOiAiUmVjbHVzdGVyaW5nIENhbmNlci1Bc3NvY2lhdGVkIEZpYnJvYmxhc3RzIFVzaW5nIFNDSVNTT1JTIgpzdWJ0aXRsZTogIkphY2sgTGVhcnkiCmF1dGhvcjogCiAgLSAiVW5pdmVyc2l0eSBvZiBOb3J0aCBDYXJvbGluYSBhdCBDaGFwZWwgSGlsbCAtIExpbmViZXJnZXIgQ29tcHJlaGVuc2l2ZSBDYW5jZXIgQ2VudGVyIgogIC0gIlVuaXZlcnNpdHkgb2YgRmxvcmlkYSAtIERlcGFydG1lbnQgb2YgQmlvc3RhdGlzdGljcyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBwYXBlcgogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgZGZfcHJpbnQ6IGthYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSAiaG9sZCIsIAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIpCnJldGljdWxhdGU6OnVzZV92aXJ0dWFsZW52KCJ+L0Rlc2t0b3AvUHl0aG9uL3NjaWVuY2UvdmVudi8iLCByZXF1aXJlZCA9IFRSVUUpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCkluIDIwMTcsIHRoZSBUdXZlc29uIExhYiBhdCBDb2xkIFNwcmluZyBIYXJib3IgQ2FuY2VyIENlbnRlciBwdWJsaXNoZWQgYSBwYXBlciB3cml0dGVuIGJ5IEVseWFkYSAqZXQgYWwqIHRoYXQgZGV0YWlsZWQgdGhlIGRpc2NvdmVyeSBvZiBjYW5jZXItYXNzb2NpYXRlZCBmaWJyb2JsYXN0cyAoQ0FGcykgaW4gbWljZS4gVGhlIHN1YnR5cGVzIHdlcmUgdGhlbiB2YWxpZGF0ZWQgaW4gaHVtYW4gc2FtcGxlcyBhZmZlY3RlZCB3aXRoIFBEQUMgaW4gYSBzdWJzZXF1ZW50IHBhcGVyIHJlbGVhc2VkIGluIDIwMTkuIEhlcmUgd2Ugd2lsbCB1c2UgU0NJU1NPUlMgdG8gaWRlbnRpZnkgdGhlIENBRiBzdWJ0eXBlcyB3aXRoaW4gdGhlIGxhcmdlciBzdHJvbWEgcG9wdWxhdGlvbiwgZmluZS1ncmFpbmVkIGltbXVuZSBjZWxsIHR5cGVzIHdpdGhpbiBicm9hZGx5LWRlZmluZWQgaW1tdW5lIGNsdXN0ZXJzLCBhbmQgZHVjdGFsICYgUERBQyBzdWJ0eXBlcyB3aXRoaW4gdGhlIGR1Y3RhbCBncm91cC4gWW91IGNhbiBpbnN0YWxsIFNDSVNTT1JTIGZyb20gW291ciBHaXRIdWIgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL2pyLWxlYXJ5Ny9TQ0lTU09SUykuCgojIExpYnJhcmllcwoKIyMgUgoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQpsaWJyYXJ5KFZBTSkgICAgICAgICAgICMgc2luZ2xlIGNlbGwgR1NFQQpsaWJyYXJ5KGRwbHlyKSAgICAgICAgICMgdGlkeSBkYXRhIApsaWJyYXJ5KFNldXJhdCkgICAgICAgICMgc2luZ2xlIGNlbGwgaW5mcmFzdHJ1Y3R1cmUKbGlicmFyeShnZ3Bsb3QyKSAgICAgICAjIHByZXR0eSBwbG90cwpsaWJyYXJ5KFNpbmdsZVIpICAgICAgICMgY2VsbCB0eXBlIGFzc2lnbm1lbnQKbGlicmFyeShqYW5pdG9yKSAgICAgICAjIGNsZWFuIGRhdGEKbGlicmFyeShkZWNvZGVycikgICAgICAjIGRlIG5vdm8gZGVjb252b2x1dGlvbiAKbGlicmFyeShTQ0lTU09SUykgICAgICAjIG91ciBwYWNrYWdlCmxpYnJhcnkobWl4dG9vbHMpICAgICAgIyBHYXVzc2lhbiBtaXh0dXJlIG1vZGVsIGVzdGltYXRpb24KbGlicmFyeShwYXRjaHdvcmspICAgICAjIGFsaWduIHBsb3RzCmxpYnJhcnkobGF0ZXgyZXhwKSAgICAgIyBMYVRlWApsaWJyYXJ5KHBhbGV0dGVlcikgICAgICMgY29sb3IgcGFsZXR0ZXMKbGlicmFyeShDT05JQ1NtYXQpICAgICAjIENOViBlc3RpbWF0aW9uCmxpYnJhcnkocmV0aWN1bGF0ZSkgICAgIyBQeXRob24gaW50ZXJmYWNlCmxpYnJhcnkoa2FibGVFeHRyYSkgICAgIyBwcmV0dHkgdGFibGVzCmxpYnJhcnkod2VzYW5kZXJzb24pICAgIyBtb3JlIGNvbG9yIHBhbGV0dGVzCmBgYAoKIyMgUHl0aG9uCgpgYGB7cHl0aG9ufQppbXBvcnQgbnVtcHkgYXMgbnAKZnJvbSBvcGVuVFNORSBpbXBvcnQgVFNORUVtYmVkZGluZwpmcm9tIG9wZW5UU05FIGltcG9ydCBpbml0aWFsaXphdGlvbgpmcm9tIG9wZW5UU05FLmFmZmluaXR5IGltcG9ydCBNdWx0aXNjYWxlCmZyb20gb3BlblRTTkUuYWZmaW5pdHkgaW1wb3J0IFBlcnBsZXhpdHlCYXNlZE5OCmBgYAoKIyBEYXRhCgpGaXJzdCB3ZSBsb2FkIGluIHRoZSAkXHRleHR7Z2VuZX0gXHRpbWVzIFx0ZXh0e2NlbGx9JCBjb3VudHMgbWF0cml4LCB0aGVuIGNyZWF0ZSBhIGBTZXVyYXRgIG9iamVjdCB0byBob2xkIGl0IGluLiBOZXh0LCB3ZSBhZGQgc2FtcGxlbmFtZSwgdGlzc3VlIHR5cGUsIGFuZCBwYXRpZW50IHNleCBtZXRhZGF0YSB0YWtlbiBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgZGF0YXNldC4KCmBgYHtyfQpyYXdfY291bnRzIDwtIFJlYWQxMFgoZGF0YS5kaXIgPSAifi9EZXNrdG9wL0RhdGEvRWx5YWRhIFJhdy9BbGwgSHVtYW4vIikKcGRhYyA8LSBDcmVhdGVTZXVyYXRPYmplY3QocmF3X2NvdW50cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAiRWx5YWRhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZmVhdHVyZXMgPSA1MDApCnBkYWNAbWV0YS5kYXRhJHNhbXBsZSA8LSBjYXNlX3doZW4oZ3JlcGwoIi0xIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi0yIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi0zIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi00Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTUiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTYiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTciLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTgiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTkiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDQiKQpwZGFjQG1ldGEuZGF0YSRjb25kaXRpb24gPC0gY2FzZV93aGVuKGdyZXBsKCItMSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItMiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItMyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNCIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiQWRqTm9ybSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItOCIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiQWRqTm9ybSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItOSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIpCnBkYWNAbWV0YS5kYXRhJHNleCA8LSBjYXNlX3doZW4oZ3JlcGwoIi0xIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJmZW1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTIiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTMiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTQiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTUiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTYiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gImZlbWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiZmVtYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi04Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJtYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi05Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJmZW1hbGUiKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpybShyYXdfY291bnRzKQpgYGAKCk5leHQsIHdlIHJlYWQgaW4gYSBkYXRhc2V0IG9mIGJhc2FsLWxpa2UgYW5kIGNsYXNzaWNhbCBQREFDIG1hcmtlciBnZW5lcyB0aGF0IHdlJ2xsIHVzZSBsYXRlciBvbiB0byBwZXJmb3JtIGVucmljaG1lbnQgYW5hbHlzaXMuIAoKYGBge3J9CmxvYWQoIn4vRGVza3RvcC9EYXRhL2NtYlN1YnR5cGVzLlJEYXRhIikKcGRhY181MF9nZW5lcyA8LSBzdWJ0eXBlR2VuZUxpc3RbWzRdXQpiYXNhbF9nZW5lcyA8LSBwZGFjXzUwX2dlbmVzW3BkYWNfNTBfZ2VuZXMkQmFzYWxMaWtlLCBdJGdlbmVTeW1ib2wKY2xhc3NpY2FsX2dlbmVzIDwtIHBkYWNfNTBfZ2VuZXNbIXBkYWNfNTBfZ2VuZXMkQmFzYWxMaWtlLCBdJGdlbmVTeW1ib2wKYGBgCgojIFByZXByb2Nlc3NpbmcKCldlIHJ1biB0aGUgdHlwaWNhbCBzaW5nbGUgY2VsbCBwcmUtcHJvY2Vzc2luZyBzdGVwcyBvbiBvdXIgY2VsbHMgLSBub3JtYWxpemF0aW9uLCBkaW1lbnNpb24gcmVkdWN0aW9uLCBhbmQgY2x1c3RlcmluZy4gCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KcGRhYyA8LSBQcmVwYXJlRGF0YShzZXVyYXQub2JqZWN0ID0gcGRhYywgCiAgICAgICAgICAgICAgICAgICAgbi5IVkcgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICBuLlBDID0gMjAsIAogICAgICAgICAgICAgICAgICAgIHJlZ3Jlc3MubXQgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgcmVncmVzcy5jYyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICB3aGljaC5kaW0ucmVkdWMgPSAidHNuZSIsIAogICAgICAgICAgICAgICAgICAgIGluaXRpYWwucmVzb2x1dGlvbiA9IDAuNCwgCiAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpCmBgYAoKTGV0J3MgY2hlY2sgb3V0IHRoZSB0LVNORSBlbWJlZGRpbmcuIEl0IGxvb2tzIGRlY2VudCwgYnV0IGNvdWxkIGRlZmluaXRlbHkgYmUgaW1wcm92ZWQuIEdsb2JhbGx5LCB0aGUgY2x1c3RlcnMgYXJlIGFycmFuZ2VkIGluIGEgYmxvYiAtIHdoaWNoIGlzbid0IHZlcnkgaW5mb3JtYXRpdmUgLSB0aG91Z2ggdGhlIGxvY2FsIHN0cnVjdHVyZSBzZWVtcyB0byBoYXZlIGJlZW4gcHJlc2VydmVkIGZhaXJseSB3ZWxsLiBWaXN1YWxseSwgdGhlcmUgYXJlIHNldmVyYWwgY2x1c3RlcnMgdGhhdCBjb250YWluIHN1Ymdyb3VwcyAtIGNsdXN0ZXJzIDMsIDQsIDUsIDYsICYgOSBsb29rIGxpa2UgZ29vZCBjYW5kaWRhdGVzIGZvciByZWNsdXN0ZXJpbmcuIAoKYGBge3J9CnAwIDwtIERpbVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgc2NhbGVfY29sb3JfcGFsZXR0ZWVyX2QoImdndGhlbWVzOjpDbGFzc2ljXzIwIikgKyAKICAgICAgbGFicyh4ID0gInQtU05FIDEiLCB5ID0gInQtU05FIDIiKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIAogICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDAKYGBgCgpXZSBjb21wdXRlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNpbGhvdWV0dGUgc2NvcmVzIGZvciBlYWNoIGNsdXN0ZXIuIAoKYGBge3J9CnNpbF9kZiA8LSBDb21wdXRlU2lsaG91ZXR0ZVNjb3JlcyhwZGFjLCBhdmcgPSBGQUxTRSkKcDEgPC0gZ2dwbG90KHNpbF9kZiwgYWVzKHggPSBDbHVzdGVyLCB5ID0gU2NvcmUsIGZpbGwgPSBDbHVzdGVyKSkgKyAKICAgICAgZ2VvbV92aW9saW4oZHJhd19xdWFudGlsZXMgPSAuNSwgY29sb3IgPSAiYmxhY2siLCBzY2FsZSA9ICJ3aWR0aCIpICsgCiAgICAgIHNjYWxlX2ZpbGxfcGFsZXR0ZWVyX2QoImdndGhlbWVzOjpDbGFzc2ljXzIwIikgKyAKICAgICAgbGFicyh5ID0gIlNpbGhvdWV0dGUgU2NvcmUiLCB4ID0gIkxvdXZhaW4gQ2x1c3RlcnMiLCBmaWxsID0gTlVMTCkgKyAKICAgICAgdGhlbWVfbWluaW1hbCgpICsgCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSksIAogICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyKSwgCiAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIpLCAKICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksIAogICAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKCksIAogICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiwgc2l6ZSA9IDEwKSkKYGBgCgpMb29raW5nIGF0IHRoZSBzaWxob3VldHRlIHNjb3JlIGRpc3RyaWJ1dGlvbiBmb3IgZWFjaCBjbHVzdGVyLCB3ZSBzZWUgdGhhdCBDbHVzdGVyIDEwIHNlZW1zIHRvIGhhdmUgdGhlIGJlc3QgZml0LCBhbmQgQ2x1c3RlcnMgMSwgMiwgJiA5IHNlZW0gdG8gaGF2ZSBwcmV0dHkgcG9vciBmaXRzLiAKCmBgYHtyfQpwMQpgYGAKCkxhc3RseSwgd2UnbGwgaWRlbnRpZnkgbWFya2VyIGdlbmVzIGZvciBlYWNoIG9mIHRoZSBjbHVzdGVycy4gCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTV9CnBkYWNfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhwZGFjLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAKdG9wNV9wZGFjX21hcmtlcnMgPC0gcGRhY19tYXJrZXJzICU+JSAKICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnAyIDwtIERvdFBsb3QocGRhYywgZmVhdHVyZXMgPSB1bmlxdWUodG9wNV9wZGFjX21hcmtlcnMkZ2VuZSksIGRvdC5zY2FsZSA9IDE1KSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gcGFsZXR0ZWVyX2QoIndlc2FuZGVyc29uOjpaaXNzb3UxIikpICsKICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIsIHkgPSAiTG91dmFpbiBDbHVzdGVyIikgKyAKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDE2LCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgCiAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLCAKICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnAyCmBgYAoKIyMgT3B0aW1pemUgRGltZW5zaW9uIFJlZHVjdGlvbgoKSSB0aGluayB0aGUgdHdvLWRpbWVuc2lvbmFsIHZpc3VhbGl6YXRpb24gb2YgdGhlIGNlbGxzIGNvdWxkIGJlIGltcHJvdmVkLiBXZSdsbCB0cnkgdXNpbmcgVU1BUCBhbmQgdGhlIEZhc3QgRm91cmllciBUcmFuc2Zvcm0tYWNjZWxlcmF0ZWQgRml0LVNORSAoYXMgaW1wbGVtZW50ZWQgaW4gdGhlIGBvcGVuVFNORWAgbGlicmFyeSkgdG8gaW1wcm92ZSB0aGUgZW1iZWRkaW5nLgoKIyMjIFVNQVAKCkl0IHNlZW1zIGxpa2UgVU1BUCBkb2VzIGEgZ29vZCBqb2Igb2YgY2xlYXJseSBzZXBhcmF0aW5nIG91ciBjbHVzdGVycyBhbmQgcHJlc2VydmluZyB0aGUgZ2xvYmFsIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4gSG93ZXZlciwgaXQncyBkaWZmaWN1bHQgdG8gc2VlIGxvY2FsIHN0cnVjdHVyZSB3aXRoaW4gc29tZSBvZiB0aGUgY2x1c3RlcnMgZHVlIHRvIHRoZWlyIGRlbnNpdHkuCgpgYGB7cn0KcGRhYyA8LSBSdW5VTUFQKHBkYWMsIAogICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInBjYSIsIAogICAgICAgICAgICAgICAgZGltcyA9IDE6MjAsIAogICAgICAgICAgICAgICAgdW1hcC5tZXRob2QgPSAidXdvdCIsIAogICAgICAgICAgICAgICAgbi5jb21wb25lbnRzID0gMiwgCiAgICAgICAgICAgICAgICBuLmVwb2NocyA9IDc1MCwgCiAgICAgICAgICAgICAgICBuLm5laWdoYm9ycyA9IDUwLCAKICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJjb3NpbmUiLCAKICAgICAgICAgICAgICAgIHNlZWQudXNlID0gNjI5LCAKICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKcDMgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidW1hcCIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICBzY2FsZV9jb2xvcl9wYWxldHRlZXJfZCgiZ2d0aGVtZXM6OkNsYXNzaWNfMjAiKSArIAogICAgICBsYWJzKHggPSAiVU1BUCAxIiwgeSA9ICJVTUFQIDIiKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsgCiAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMwpgYGAKCiMjIyBGaXQtU05FCgpGb3IgaW5mb3JtYXRpb24gb24gaG93IHRvIGluc3RhbGwgdGhlIGBvcGVuVFNORWAgaW1wbGVtZW50YXRpb24gb2YgRml0LVNORSBhbmQgaG93IHRvIHJ1biB0aGUgYWxnb3JpdGhtLCBwbGVhc2UgdmlzaXQgW3RoZSBleGNlbGxlbnQgR2l0SHViIHJlcG9zaXRvcnkgb2YgUGF2bGluIFBvbGljYXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9wYXZsaW4tcG9saWNhci9vcGVuVFNORSkuCgpGaXJzdCB3ZSdsbCBydW4gYSBzaW1wbGUsIHN0YW5kYXJkIEZpdC1TTkUgZW1iZWRkaW5nLiBJdCdzIG5lY2Vzc2FyeSB0byBtYWtlIHRoZSBQQ0EgZW1iZWRkaW5ncyBhY2Nlc3NpYmxlIGJ5IFB5dGhvbi4KCmBgYHtyfQpwY19kZiA8LSBFbWJlZGRpbmdzKHBkYWMsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKcGNfZGYgPSBucC5hcnJheShyLnBjX2RmKQojIHJ1biBGaXQtU05FCmFmZmluID0gUGVycGxleGl0eUJhc2VkTk4ocGNfZGYsIHBlcnBsZXhpdHk9MzAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShwY19kZiwgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZTEgPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkMSA9IHRzbmUxLm9wdGltaXplKG5faXRlcj0zNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC42KSAKZW1iZWQyID0gZW1iZWQxLm9wdGltaXplKG5faXRlcj03NTAsIG1vbWVudHVtPTAuOCkKYGBgCgpUaGUgZW1iZWRkaW5nIGxvb2tzIGdvb2QsIHNvIHdlJ2xsIHVzZSBpdCBnb2luZyBmb3J3YXJkcy4KCmBgYHtyfQplbWJlZCA8LSBhcy5tYXRyaXgocHkkZW1iZWQyKQpyb3duYW1lcyhlbWJlZCkgPC0gY29sbmFtZXMocGRhYykKcGRhY0ByZWR1Y3Rpb25zJGZpdHNuZSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDQgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAiZml0c25lIiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgIHNjYWxlX2NvbG9yX3BhbGV0dGVlcl9kKCJnZ3RoZW1lczo6Q2xhc3NpY18yMCIpICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsKICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA0CmBgYAoKRHVlIHRvIHRoZSB3YXkgYFNldXJhdGAgYWNjZXNzZXMgY2VsbCBlbWJlZGRpbmdzLCB3ZSdsbCBuZWVkIHRvIHJlcGxhY2Ugb3VyIG9yaWdpbmFsIHQtU05FIGRpbWVuc2lvbiByZWR1Y3Rpb24gaW4gb3VyIGBTZXVyYXRgIG9iamVjdCB3aXRoIHRoZSBuZXcgRml0LVNORSB2ZXJzaW9uLiBXZSdsbCBrZWVwIHRoZSBvcmlnaW5hbCBCYXJuZXMtSHV0IHQtU05FIGVtYmVkZGluZyB1bmRlciBhIHNlcGFyYXRlIG5hbWUuCgpgYGB7cn0KcGRhY0ByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gcGRhY0ByZWR1Y3Rpb25zJHRzbmUKcGRhY0ByZWR1Y3Rpb25zJHRzbmUgPC0gcGRhY0ByZWR1Y3Rpb25zJGZpdHNuZQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30Kcm0oZW1iZWQsIHBjX2RmKQpnYyh2ZXJib3NlID0gRkFMU0UpCmBgYAoKIyBTaW5nbGVSIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKIyMgU2luZ2xlIENlbGwgUk5BLXNlcSBSZWZlcmVuY2UgRGF0YQoKSGVyZSB3ZSB1c2UgdGhlIGBTaW5nbGVSYCBwYWNrYWdlIHRvIGlkZW50aWZ5IGJyb2FkIGNlbGwgdHlwZXMuIFRoZSByZWZlcmVuY2UgZGF0YXNldCB3ZSBsb2FkIGlzIGFuIGBzY3RyYW5zZm9ybWAtbm9ybWFsaXplZCB2ZXJzaW9uIG9mIHRoZSByYXcgY291bnRzIGF2YWlsYWJsZSBpbiBgc2NSTkFzZXE6OkJhcm9uUGFuY3JlYXNEYXRhKClgLCB3aGljaCBjb25zaXN0cyBvZiBub3JtYWwgcGFuY3JlYXMgY2VsbHMgdGhhdCB3ZXJlIHNlcXVlbmNlZCBhbmQgYW5ub3RhdGVkIGJ5IHRoZSByZXNlYXJjaGVycy4KCmBgYHtyfQpzY19yZWYgPC0gcmVhZFJEUygiL1ZvbHVtZXMvbGFicy9Ib21lL0plbiBKZW4gWWVoIExhYi9KYWNrL3NjUk5Bc2VxL1NldXJhdC9zaW5nbGVfY2VsbF9yZWZfbm9ybWFsaXplZC5SZHMiKQpzY19wcmVkcyA8LSBTaW5nbGVSKHRlc3QgPSBkYXRhLmZyYW1lKHBkYWNAYXNzYXlzJFNDVEBkYXRhKSwgCiAgICAgICAgICAgICAgICAgICAgcmVmID0gc2NfcmVmLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY19yZWYkbGFiZWwsIAogICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJjbHVzdGVyIiwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMgPSBwZGFjJHNldXJhdF9jbHVzdGVycywgCiAgICAgICAgICAgICAgICAgICAgZGUubWV0aG9kID0gIndpbGNveCIpCnBkYWNbWyJTaW5nbGVSLmxhYmVscy5zYyJdXSA8LSBzY19wcmVkcyRsYWJlbHNbbWF0Y2gocGRhY1tbXV1bWyJzZXVyYXRfY2x1c3RlcnMiXV0sIHJvd25hbWVzKHNjX3ByZWRzKSldCnBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPC0gY2FzZV93aGVuKHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gImFjaW5hciIgfiAiQWNpbmFyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gImFjdGl2YXRlZF9zdGVsbGF0ZSIgfiAiQWN0aXZhdGVkIFN0ZWxsYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAiZHVjdGFsIiB+ICJEdWN0YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAibWFjcm9waGFnZSIgfiAiTWFjcm9waGFnZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gInRfY2VsbCIgfiAiVCIpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlJ3MgYSBsYXJnZSBpbW11bmUgcG9wdWxhdGlvbiwgYXMgd2VsbCBhcyBzbWFsbGVyIGR1Y3RhbCwgZmlicm9ibGFzdCAoZGVub3RlZCBhY3RpdmF0ZWQgc3RlbGxhdGUgaW4gdGhlIHJlZmVyZW5jZSBkYXRhc2V0KSwgYW5kIGFjaW5hciBncm91cHMuIFRoZXNlIGJyb2FkIGNlbGwgdHlwZXMgbGluZSB1cCB3aXRoIHdoYXQgd2UgZXhwZWN0ZWQgdG8gc2VlIGdpdmVuIHRoZSBhdXRob3JzJyBvcmlnaW5hbCBjZWxsIGNsdXN0ZXIgYW5ub3RhdGlvbnMuIAoKYGBge3J9CnA1IDwtIERpbVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJTaW5nbGVSLmxhYmVscy5zYyIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA1CmBgYAoKIyMgQnVsayBUaXNzdWUgUk5BLXNlcSBSZWZlcmVuY2UgRGF0YQoKVGhpcyBkYXRhc2V0IGlzIGNvbXBvc2VkIG9mIGxhYmVsZWQgJiBsb2ctbm9ybWFsaXplZCBidWxrIFJOQS1zZXEgc2FtcGxlcyBmcm9tIHRoZSBIdW1hbiBQcmltYXJ5IENlbGwgQXRsYXMuCgpgYGB7cn0KYnVsa19yZWYgPC0gSHVtYW5QcmltYXJ5Q2VsbEF0bGFzRGF0YSgpCmJ1bGtfcHJlZHMgPC0gU2luZ2xlUih0ZXN0ID0gZGF0YS5mcmFtZShwZGFjQGFzc2F5cyRTQ1RAZGF0YSksIAogICAgICAgICAgICAgICAgICAgICAgcmVmID0gYnVsa19yZWYsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYnVsa19yZWYkbGFiZWwubWFpbiwgCiAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiY2x1c3RlciIsIAogICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMgPSBwZGFjJHNldXJhdF9jbHVzdGVycywgCiAgICAgICAgICAgICAgICAgICAgICBkZS5tZXRob2QgPSAid2lsY294IikKcGRhY1tbIlNpbmdsZVIubGFiZWxzLmJ1bGsiXV0gPC0gYnVsa19wcmVkcyRsYWJlbHNbbWF0Y2gocGRhY1tbXV1bWyJzZXVyYXRfY2x1c3RlcnMiXV0sIHJvd25hbWVzKGJ1bGtfcHJlZHMpKV0KcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrIDwtIGNhc2Vfd2hlbihwZGFjJFNpbmdsZVIubGFiZWxzLmJ1bGsgPT0gIkJfY2VsbCIgfiAiQiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuYnVsayA9PSAiRXBpdGhlbGlhbF9jZWxscyIgfiAiRXBpdGhlbGlhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuYnVsayA9PSAiQl9jZWxsLSIgfiAiQiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuYnVsayA9PSAiVF9jZWxscyIgfiAiVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IHBkYWMkU2luZ2xlUi5sYWJlbHMuYnVsaykKYGBgCgpUaGUgYnVsayByZWZlcmVuY2UgZ2l2ZXMgdXMgc29tZXdoYXQgbW9yZSBncmFudWxhciBsYWJlbHMgZm9yIHRoZSBpbW11bmUgY2VsbHMsIGFuZCBjb25maXJtcyB0aGUgaWRlbnRpdGllcyBvZiB0aGUgZHVjdGFsIC8gZXBpdGhlbGlhbCBhbmQgc3Ryb21hIGNsdXN0ZXJzLiAKCmBgYHtyfQpwNiA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAiU2luZ2xlUi5sYWJlbHMuYnVsayIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA2CmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpybShzY19wcmVkcywgYnVsa19wcmVkcywgYnVsa19yZWYsIHNjX3JlZikKZ2ModmVyYm9zZSA9IEZBTFNFKQpgYGAKCk9uZSBzaG91bGRuJ3QgdXNlIGBTaW5nbGVSYCBhcyB0aGUgZmluYWwgYXV0aG9yaXR5IGZvciBjZWxsIHR5cGVzLCBidXQgd2Ugd2VyZSBhYmxlIHRvIGNvbmZpcm0gdGhlIGlkZW50aXRpZXMgb2YgdGhlIGR1Y3RhbCBhbmQgZmlicm9ibGFzdCBjbHVzdGVycywgd2hpY2ggaXMgaW1wb3J0YW50IGZvciB0aGlzIGRhdGFzZXQgYXMgdGhlIGNlbGxzIHdlIGFyZSBtb3N0IGludGVyZXN0ZWQgaW4gYXJlIHRoZSBjYW5jZXItYXNzb2NpYXRlZCBmaWJyb2JsYXN0cyAoQ0FGcykuIAoKIyBDT05JQ1NtYXQgQ05WIEVzdGltYXRpb24KCk5leHQgd2UnbGwgYXR0ZW1wdCB0byBpZGVudGlmeSBtYWxpZ25hbnQgY2VsbHMgdXNpbmcgc2luZ2xlLWNlbGwgY29weSBudW1iZXIgdmFyaWF0aW9uIGVzdGltYXRpb24gYXMgaW1wbGVtZW50ZWQgaW4gdGhlIGBDT05DSVNtYXRgIHBhY2thZ2UuIERldGFpbHMgb2YgdGhlIEdNTSBtZXRob2RvbG9neSB1c2VkIGNhbiBiZSBmb3VuZCBhdCBbdGhlIERpYXogTGFiJ3MgR2l0SHViIHJlcG9zaXRvcnldKGh0dHBzOi8vZ2l0aHViLmNvbS9kaWF6bGFiL0NPTklDUykuIE5vdGU6IHRoaXMgc3RlcCBpcyBtZW1vcnktaW50ZW5zaXZlIGJlY2F1c2UgMSkgaXQgcmVxdWlyZXMgdGhlIHNwYXJzZSBjb3VudHMgbWF0cml4IHRvIGJlIGNhc3QgdG8gYSBkZW5zZSBtYXRyaXggYW5kIDIpIGEgbG90IG9mIEdhdXNzaWFuIG1peHR1cmUgbW9kZWxzIGdldCBlc3RpbWF0ZWQuIElmIHlvdXIgbWFjaGluZSBkb2Vzbid0IGhhdmUgYSBsb3Qgb2YgUkFNIGl0IG1pZ2h0IGJlIGJlc3QgdG8gc2tpcCB0aGlzIGFuZCBtYW51YWxseSBhbm5vdGF0ZSB0aGUgbWFsaWduYW50IGNlbGxzIGluc3RlYWQgdGhyb3VnaCB0aGUgdXNhZ2Ugb2YgY2Fub25pY2FsIG1hcmtlcnMgb3IgdGhlIGBWQU1gIHNpbmdsZS1jZWxsIEdTRUEgbWV0aG9kb2xvZ3kuIAoKYGBge3IsIHJlc3VsdHM9ImhpZGUifQpjaHJvbV9yZWdpb25zIDwtIHJlYWQudGFibGUoIi9Wb2x1bWVzL2xhYnMvSG9tZS9KZW4gSmVuIFllaCBMYWIvSmFjay9zY1JOQXNlcS9jaHJvbV9hcm1fcG9zaXRpb25zLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUpCmdlbmVfcG9zIDwtIGdldEdlbmVQb3NpdGlvbnMocm93bmFtZXMocGRhYykpCmNwbSA8LSB0KHQoYXMubWF0cml4KHBkYWNAYXNzYXlzJFNDVEBjb3VudHMpKSAvIGNvbFN1bXMoYXMubWF0cml4KHBkYWNAYXNzYXlzJFNDVEBjb3VudHMpKSkgKiAxMF41CmNwbSA8LSBsb2cyKGNwbSArIDEpCm5vcm1fZmFjdG9yIDwtIGNhbGNOb3JtRmFjdG9ycyhjcG0pCmNudl9lc3QgPC0gcGxvdEFsbChtYXQgPSBjcG0sIAogICAgICAgICAgICAgICAgICAgbm9ybUZhY3RvciA9IG5vcm1fZmFjdG9yLCAKICAgICAgICAgICAgICAgICAgIHJlZ2lvbnMgPSBjaHJvbV9yZWdpb25zLCAKICAgICAgICAgICAgICAgICAgIGdlbmVfcG9zID0gZ2VuZV9wb3MsIAogICAgICAgICAgICAgICAgICAgZm5hbWUgPSAiRWx5YWRhIikKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CmdjKHZlcmJvc2UgPSBGQUxTRSkKYGBgCgojIyBWaXN1YWxpemluZyBDTlZzCgpBZnRlciBlc3RpbWF0aW5nIENOVnMsIHdlIGNsdXN0ZXIgdGhlIGNlbGxzIGludG8gJGsgPSAzJCBjbHVzdGVycywgd2l0aCB0aGUgaG9wZSBvZiBmaW5kaW5nIG9uZSBsYXJnZSBjbHVzdGVyIG9mIG5vcm1hbCBjZWxscyBhbmQgdHdvIHNtYWxsZXIgY2x1c3RlcnMgY29tcG9zZWQgb2YgQ0FGcyBhbmQgUERBQyBjZWxscy4gCgpgYGB7cn0KYmljX3RhYmxlIDwtIHJlYWQudGFibGUoIi4vRWx5YWRhX0JJQ19MUi50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGQUxTRSkKY2FuZF9yZWdpb25zIDwtIHJvd25hbWVzKGJpY190YWJsZVtiaWNfdGFibGUkYEJJQyBkaWZmZXJlbmNlYCA+IDEwMDAgJiBiaWNfdGFibGUkYExSVCBhZGouIHAtdmFsYCA8IC4wMSwgXSkKcGRmKCJ+L0Rlc2t0b3AvUi9TQ0lTU09SUy92aWduZXR0ZXMvZmlndXJlc19zdXBwL0VseWFkYS9DT05JQ1NtYXRfSGVhdG1hcC5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2KQpoaXN0MSA8LSBwbG90SGlzdG9ncmFtKGNudl9lc3RbLCBjYW5kX3JlZ2lvbnNdLCAKICAgICAgICAgICAgICAgICAgICAgICBjcG0sIAogICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJzID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgenNjb3JlVGhyZXNob2xkID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgY2VsbHR5cGVzID0gcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrLCAKICAgICAgICAgICAgICAgICAgICAgICBwYXRpZW50cyA9IHBkYWMkc2FtcGxlKQpkZXYub2ZmKCkKYGBgCgpXZSBhZGQgdGhlIG5vcm1hbCB2cy4gbWFsaWduYW50IGNlbGwgbGFiZWxzIGluIHRvIG91ciBgU2V1cmF0YCBvYmplY3QncyBtZXRhZGF0YSwgdGhlbiB2aXN1YWxpemUgdGhlIHJlc3VsdHMuIEFzIGV4cGVjdGVkLCB0aGUgbWFsaWduYW50IGNlbGxzIGFyZSBsb2NhdGVkIGluIHRoZSBjbHVzdGVycyBpZGVudGlmaWVkIGJ5IGBTaW5nbGVSYCBhcyBkdWN0YWwgY2VsbHMgYW5kIGZpYnJvYmxhc3RzLiBUaGlzIGluZGljYXRlcyB0aGF0IGBDT05JQ1NtYXRgIGRpZCBhIHNvbGlkIGpvYiBvZiBlc3RpbWF0aW5nIHRoZSBDTlZzIC0gbm8gZWFzeSBmZWF0IHdpdGggc3BhcnNlLCBub2lzeSBzaW5nbGUtY2VsbCBkYXRhLiAKCmBgYHtyfQpub3JtYWwgPC0gd2hpY2goaGlzdDEgPT0gMSkKbWFsaWduYW50IDwtIHdoaWNoKGhpc3QxICE9IDEpCnBkYWNAbWV0YS5kYXRhJG1hbGlnIDwtIGlmZWxzZShyb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkgJWluJSBuYW1lcyhub3JtYWwpLCAiTm9ybWFsIiwgIk1hbGlnbmFudCIpCnA3IDwtIERpbVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJtYWxpZyIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlppc3NvdTEiLCBuID0gNSlbYyg1LCAyKV0pICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNwpgYGAKCldoZW4gbG9va2luZyBhdCB0aGUgYFNpbmdsZVJgIGxhYmVscyBmcm9tIHRoZSBidWxrIHJlZmVyZW5jZSwgd2Ugc2VlIHRoYXQgdGhlIEVwaXRoZWxpYWwgKER1Y3RhbCkgYW5kIE1lc2VuY2h5bWFsIFN0ZW0gQ2VsbCAoRmlicm9ibGFzdCkgY2x1c3RlcnMgaGF2ZSB0aGUgaGlnaGVzdCBwcm9wb3J0aW9ucyBvZiBtYWxpZ25hbnQgY2VsbHMsIHdoaWNoIGlzIGV4YWN0bHkgd2hhdCB3ZSBleHBlY3RlZCB0byBzZWUuIAoKYGBge3J9CnBkYWNAbWV0YS5kYXRhICU+JSAKICBncm91cF9ieShTaW5nbGVSLmxhYmVscy5idWxrKSAlPiUgCiAgc3VtbWFyaXNlKE1lYW5NYWxpZyA9IG1lYW4oY2FzZV93aGVuKG1hbGlnID09ICJNYWxpZ25hbnQiIH4gMSwgVFJVRSB+IDApKSkgJT4lIAogIG11dGF0ZShNZWFuTWFsaWcgPSBmb3JtYXR0YWJsZTo6cGVyY2VudChNZWFuTWFsaWcpKSAlPiUgCiAga2JsKGJvb2t0YWJzID0gVFJVRSwgY29sLm5hbWVzID0gYygiQnVsayBSZWZlcmVuY2UgU2luZ2xlUiBMYWJlbCIsICIlIE1hbGlnbmFudCBDZWxscyIpKSAlPiUgCiAga2FibGVfbWluaW1hbChmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpybShjcG0sIGJpY190YWJsZSwgY2hyb21fcmVnaW9ucywgY252X2VzdCwgZ2VuZV9wb3MsIGNhbmRfcmVnaW9ucywgaGlzdDEsIG5vcm1hbCwgbm9ybV9mYWN0b3IsIG1hbGlnbmFudCkKZ2ModmVyYm9zZSA9IEZBTFNFKSAgIyBub3QgcmVjb21tZW5kZWQsIGJ1dCBpdCBjb3VsZCBoZWxwIHRoaXMgZG9jdW1lbnQgY29tcGlsZSwgc28gLi4uCmBgYAoKIyBERUNPREVSCgpOZXh0LCB3ZSB1c2UgW0RyLiBYaWFubHUgUGVuZydzIERFQ09ERVJdKGh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyYXBlbmcvZGVjb2RlcnIpIGluIG9yZGVyIHRvIGRlY29udm9sdmUgdGhlIGRhdGFzZXQgYW5kIGFzc2lnbiB3ZWlnaHRzIHRvIGVhY2ggY2VsbCB1c2luZyBub24tbmVnYXRpdmUgbWF0cml4IGZhY3Rvcml6YXRpb24uIFdlIGNhbGN1bGF0ZSBiYXNhbCAmIGNsYXNzaWNhbCBQREFDLCBub3JtYWwgJiBhY3RpdmF0ZWQgc3Ryb21hLCBpbW11bmUsIGFuZCBlbmRvY3JpbmUgJiBleG9jcmluZSBwYW5jcmVhcyBjb21wYXJ0bWVudCB3ZWlnaHRzLgoKYGBge3J9CnNhbXBsZV93dHNfdW5zY2FsZWQgPC0gRGVjb25fc2luZ2xlX3NhbXBsZShyZWZTZXQgPSAiVENHQV9STkFzZXFfUEFBRCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHBkYWNAYXNzYXlzJFNDVEBkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVJRFR5cGUgPSAiZ2VuZVN5bWJvbCIpCnNhbXBsZV93dHMgPC0gTm9ybV9QREFDX3dlaWdodHMoc2FtcGxlX3d0c191bnNjYWxlZCkKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzJEltbXVuZSwgImltbXVuZSIpCnBkYWMgPC0gQWRkTWV0YURhdGEocGRhYywgc2FtcGxlX3d0cyRiY1JhdGlvLCAiYmNfcmF0aW8iKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkRXhvY3JpbmUsICJleG9jcmluZSIpCnBkYWMgPC0gQWRkTWV0YURhdGEocGRhYywgc2FtcGxlX3d0cyRFbmRvY3JpbmUsICJlbmRvY3JpbmUiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHNfdW5zY2FsZWRbLCA5XSwgImJhc2FsIikKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzX3Vuc2NhbGVkWywgNV0sICJjbGFzc2ljYWwiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkTm9ybWFsU3Ryb21hLCAibm9ybV9zdHJvbWEiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkQWN0aXZhdGVkU3Ryb21hLCAiYWN0X3N0cm9tYSIpCmBgYAoKIyMgVmlzdWFsaXppbmcgREVDT0RFUiBXZWlnaHRzCgojIyMgQmFzYWwgUERBQwoKVGhlIGJhc2FsIHdlaWdodHMgYXJlIGhpZ2hlc3QgaW4gYSBzdWJjbHVzdGVyIG9mIHRoZSBkdWN0YWwgZ3JvdXAgaWRlbnRpZmllZCB0aHJvdWdoIGBTaW5nbGVSYC4gVGhpcyBpcyBpbnRlcmVzdGluZyBhcyB0aGUgYXV0aG9ycyBkaWQgbm90IGZpbmQgZXZpZGVuY2Ugb2YgdGhlIGJhc2FsIHN1YnR5cGUgaW4gdGhlaXIgcGFwZXIuIAoKYGBge3J9CnA4IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYmFzYWwiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBOb0xlZ2VuZCgpCnA4CmBgYAoKIyMjIENsYXNzaWNhbCBQREFDCgpUaGUgY2xhc3NpY2FsIHdlaWdodHMgYXJlIGhpZ2hlc3QgaW4gYW5vdGhlciBzdWJjbHVzdGVyIG9mIHRoZSBkdWN0YWwgY2x1c3RlciwgYW5kIGNlbGxzIHdpdGggaGlnaCBjbGFzc2ljYWwgd2VpZ2h0cyBkbyBub3QgY29sbG9jYXRlIHdpdGggdGhvc2UgdGhhdCBoYXZlIGhpZ2ggYmFzYWwgd2VpZ2h0cy4gVGhlIHB1dGF0aXZlIGNsYXNzaWNhbCBhbmQgYmFzYWwgUERBQyBjZWxscyBhbHNvIGFsaWduIGNsb3NlbHkgd2l0aCB0aGUgY2VsbHMgaWRlbnRpZmllZCB0aHJvdWdoIGBDT05DSVNtYXRgIGFzIG1hbGlnbmFudC4gCgpgYGB7cn0KcDkgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJjbGFzc2ljYWwiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBOb0xlZ2VuZCgpCnA5CmBgYAoKIyMjIEV4b2NyaW5lIFBhbmNyZWFzCgpUaGUgY2x1c3RlciBpZGVudGlmaWVkIHRocm91Z2ggYFNpbmdsZVJgIGFzIGFjaW5hciBjZWxscyBpcyB0aGUgb25seSBjbHVzdGVyIHdpdGggaGlnaCBleG9jcmluZSBwYW5jcmVhcyB3ZWlnaHRzLiAKCmBgYHtyfQpwMTAgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJleG9jcmluZSIsIHB0LnNpemUgPSAwLjc1KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpCnAxMApgYGAKCiMjIyBFbmRvY3JpbmUgUGFuY3JlYXMKCk5vIGNlbGxzIGhhdmUgaGlnaCBlbmRvY3JpbmUgcGFuY3JlYXMgd2VpZ2h0cy4gCgpgYGB7cn0KcDExIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiZW5kb2NyaW5lIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDExCmBgYAoKIyMjIEltbXVuZQoKT25jZSBhZ2Fpbiwgd2UgY29uZmlybSB0aGUgbGFyZ2VuZXNzIG9mIHRoZSBpbW11bmUgY2VsbCBwb3B1bGF0aW9uIGluIHRoaXMgZGF0YXNldC4gCgpgYGB7cn0KcDEyIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiaW1tdW5lIiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpCnAxMgpgYGAKCiMjIyBOb3JtYWwgU3Ryb21hCgpDZWxscyB3aXRoIGhpZ2ggbm9ybWFsIHN0cm9tYSBzdHJvbWEgd2VpZ2h0cyBhcmUgbG9jYXRlZCBpbiB0aGUgY2x1c3RlciBpZGVudGlmaWVkIGJ5IGBTaW5nbGVSYCBhcyBiZWluZyBzdHJvbWFsIGNlbGxzLiAKCmBgYHtyfQpwMTMgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJub3JtX3N0cm9tYSIsIHB0LnNpemUgPSAwLjc1KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpCnAxMwpgYGAKCiMjIyBBY3RpdmF0ZWQgU3Ryb21hCgpDZWxscyB3aXRoIGhpZ2ggYWN0aXZhdGVkIHN0cm9tYSB3ZWlnaHRzIGFyZSBhbHNvIGxvY2F0ZWQgaW4gdGhlIGZpYnJvYmxhc3QgY2x1c3RlciwgYW5kIGRvIG5vdCBpbnRlcnNlY3Qgd2l0aCB0aGUgY2VsbHMgdGhhdCBoYXZlIGhpZ2ggbm9ybWFsIHN0cm9tYSBzY29yZXMuIFRoaXMgaW5kaWNhdGVzIHRoYXQgYFNDSVNTT1JTYCB3aWxsIG1vc3QgbGlrZWx5IHBlcmZvcm0gd2VsbCBvbiB0aGUgZmlicm9ibGFzdCBjbHVzdGVyIGFuZCBiZSBhYmxlIHRvIHF1aWNrbHkgdGVhc2Ugb3V0IHRoZSBjZWxsIHN1YnR5cGVzLgoKYGBge3J9CnAxNCA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImFjdF9zdHJvbWEiLCBwdC5zaXplID0gMC43NSkgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKQpwMTQKYGBgCgojIFNDSVNTT1JTCgpOb3cgdGhhdCB3ZSBoYXZlIHJvdWdoIGxhYmVscyBmcm9tIGBTaW5nbGVSYCwgQ05WcyBmcm9tIGBDT05JQ1NtYXRgLCBhbmQgY29tcGFydG1lbnQgd2VpZ2h0cyBmcm9tIGBERUNPREVSYCwgd2Ugc2hvdWxkIGhhdmUgbW9yZSB0aGFuIGVub3VnaCBjZWxsLWxldmVsIG1ldGFkYXRhIHRvIGxvb2sgZm9yIGFuZCBhbm5vdGF0ZSBjZWxsIHN1YnR5cGVzIHVzaW5nIGBTQ0lTU09SU2AuIAoKIyMgRmlicm9ibGFzdHMKClRoZSBmaWJyb2JsYXN0IG1hcmtlciBnZW5lcyBwcm92aWRlZCBieSBFbHlhZGEgKmV0IGFsKiBtYXRjaCB0aGUgYFNpbmdsZVJgIHJlc3VsdHMgZGVmaW5pbmcgY2x1c3RlciA2IGFzIGNvbnRhaW5pbmcgZmlicm9ibGFzdHMuIAoKYGBge3J9CnAxNSA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNPTDFBMSIsIHB0LnNpemUgPSAwLjc1KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIkNPTDFBMSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDE2IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ09MM0ExIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiQ09MM0ExIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTcgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMVU0iLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiTFVNIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTggPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJEQ04iLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiRENOIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDE1IHwgcDE2KSAvIChwMTcgfCBwMTgpCmBgYAoKSGVyZSdzIHRoZSBjZWxscyB3ZSdsbCBiZSByZWNsdXN0ZXJpbmcuIAoKYGBge3J9CmZpYnJvX2NlbGxzIDwtIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhW3BkYWNAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyA9PSA2LCBdKQpwMTkgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGNlbGxzLmhpZ2hsaWdodCA9IGZpYnJvX2NlbGxzLCBjb2xzLmhpZ2hsaWdodCA9ICJuYXZ5IiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDE5IC8gcDQKYGBgCgojIyMgUmVjbHVzdGVyaW5nCgpIZXJlIHdlIHVzZSBgUmVjbHVzdGVyQ2VsbHMoKWAgdG8gaWRlbnRpZnkgc3ViY2x1c3RlcnMgd2l0aGluIGNsdXN0ZXIgNi4gV2UgZmluZCBmaXZlIGRpc3RpbmN0IHN1YmNsdXN0ZXJzLgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmZpYnJvIDwtIFJlY2x1c3RlckNlbGxzKHBkYWMsCiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gNiwgCiAgICAgICAgICAgICAgICAgICAgICAgIG4uSFZHID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAyMCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjAzLCAuMDUsIC4xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGsudmFscyA9IGMoMjAsIDMwLCA0MCksIAogICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUpCmZpYnJvX3BjIDwtIEVtYmVkZGluZ3MoZmlicm8sICJwY2EiKQpgYGAKCldlJ2xsIGFnYWluIHJ1biBGaXQtU05FIG9uIHRoZSByZWNsdXN0ZXJlZCBjZWxscywgZm9yIGNvbnNpc3RlbmNpZXMgc2FrZS4gCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCmZpYnJvX3BjID0gci5maWJyb19wYwojIHJ1biBGaXQtU05FCmFmZmluX2ZpYnJvID0gUGVycGxleGl0eUJhc2VkTk4oZmlicm9fcGMsIHBlcnBsZXhpdHk9NDAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShmaWJyb19wYywgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZV9mID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9maWJybywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9mMSA9IHRzbmVfZi5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249NSwgbW9tZW50dW09MC40KSAKZW1iZWRfZjIgPSBlbWJlZF9mMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKClB1bGxpbmcgdGhlIHJlc3VsdHMgYmFjayBpbnRvIFIgYW5kIHZpc3VhbGl6aW5nIHRoZW0gc2hvd3MgY2xlYXIgc2VwYXJhdGlvbiBiZXR3ZWVuIHRoZSBzdWJjbHVzdGVycy4gVGhlcmUncyBzb21lIG5vaXNlIGluIHN1YmNsdXN0ZXIgMCwgYnV0IG90aGVyIHRoYW4gdGhhdCB0aGUgcmVlbWJlZGRpbmcgbG9va3Mgc29saWQuIAoKYGBge3J9CmVtYmVkX2ZpYnJvIDwtIGFzLm1hdHJpeChweSRlbWJlZF9mMikKcm93bmFtZXMoZW1iZWRfZmlicm8pIDwtIGNvbG5hbWVzKGZpYnJvKQpmaWJyb0ByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gZmlicm9AcmVkdWN0aW9ucyR0c25lCmZpYnJvQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9maWJybywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwMjAgPC0gRGltUGxvdChmaWJybywgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMjAKYGBgCgojIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgpGaXJzdCB3ZSBpZGVudGlmeSB0aGUgZW5kb3RoZWxpYWwgYW5kIHBlcml2YXNjdWxhciBjZWxscyB1c2luZyBQTFZBUCBhbmQgUkdTNSBleHByZXNzaW9uLiAKCmBgYHtyfQpwMjEgPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUExWQVAiLCBwdC5zaXplID0gMS41KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIlBMVkFQIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMjIgPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUkdTNSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIlJHUzUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMjEgfCBwMjIpIC8gcDIwCmBgYAoKCk5leHQsIHdlIHVzZSB0aGUgYFZBTWAgbWV0aG9kIG9mIHNpbmdsZSBjZWxsIGdlbmUgc2V0IGVucmljaG1lbnQgYW5hbHlzaXMgdG8gZGV0ZXJtaW5lIHdoaWNoIGNsdXN0ZXJzIGFyZSBlbnJpY2hlZCBmb3IgdGhlIGlDQUYgYW5kIG15Q0FGIG1hcmtlciBnZW5lcywgYXMgd2VsbCBhcyB0aGUgZ2VuZXJhbCBwYW4tQ0FGIG1hcmtlciBzZXQuIFdlIHVzZSB0aGUgbWFya2VyIGdlbmVzIGlkZW50aWZpZWQgYnkgdGhlIGF1dGhvcnMuIAoKYGBge3J9CmljYWZfZ2VuZXMgPC0gYygiSUw2IiwgIlBER0ZSQSIsICJDWENMMTIiLCAiQ0ZEIiwgIkxNTkEiLCAiQUdUUjEiLCAiSEFTMSIsICJDWENMMSIsICJDWENMMiIsICJDQ0wyIiwgIklMOCIpCm15Y2FmX2dlbmVzIDwtIGMoIkFDVEEyIiwgIlRBR0xOIiwgIk1NUDExIiwgIk1ZTDkiLCAiSE9QWCIsICJQT1NUTiIsICJUUE0xIiwgIlRQTTIiKQpwYW5fY2FmX2dlbmVzIDwtIGMoIkNPTDFBMSIsICJGQVAiLCAiUERQTiIsICJEQ04iLCAiVklNIikKZ2VuZV9zZXRzIDwtIGxpc3QoaWNhZl9nZW5lcywgbXljYWZfZ2VuZXMsIHBhbl9jYWZfZ2VuZXMpCm5hbWVzKGdlbmVfc2V0cykgPC0gYygiaUNBRiIsICJteUNBRiIsICJQYW4tQ0FGIikKZm9yIChpIGluIHNlcShnZW5lX3NldHMpKSB7CiAgZ2VuZV9zZXRzW1tpXV0gPC0gZ2VuZV9zZXRzW1tpXV1bZ2VuZV9zZXRzW1tpXV0gJWluJSByb3duYW1lcyhmaWJybyldCn0KZmlicm8gPC0gdmFtRm9yU2V1cmF0KGZpYnJvLCAKICAgICAgICAgICAgICAgICAgICAgIGdlbmUuc2V0LmNvbGxlY3Rpb24gPSBnZW5lX3NldHMsIAogICAgICAgICAgICAgICAgICAgICAgZ2FtbWEgPSBUUlVFKQpEZWZhdWx0QXNzYXkoZmlicm8pIDwtICJWQU1jZGYiCmBgYAoKIyMjIyBpQ0FGcyAmIG15Q0FGcwoKV2UgY2FuIGVhc2lseSBkZWZpbmUgY2x1c3RlciAwIGFzIHRoZSBteUNBRiBwb3B1bGF0aW9uLCBhbmQgY2x1c3RlciAyIGFzIHRoZSBzbGlnaHRseSBzbWFsbGVyIGlDQUYgcG9wdWxhdGlvbi4gQ2x1c3RlciA0IHNob3dzIG5vIGVucmljaG1lbnQgd2hhdHNvZXZlciBmb3IgZWl0aGVyIHRoZSBpQ0FGIG9yIG15Q0FGIGdlbmUgc2V0cy4gCgpgYGB7cn0KcDIzIDwtIEZlYXR1cmVQbG90KGZpYnJvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImlDQUYiLCBwdC5zaXplID0gMS41KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gImlDQUYiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAyNCA8LSBGZWF0dXJlUGxvdChmaWJybywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJteUNBRiIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIm15Q0FGIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDIzIHwgcDI0KSAvIHAyMApgYGAKCiMjIyMgYXBDQUZzCgpTbyB3ZSBoYXZlIGEgc21hbGwgY2x1c3RlciBvZiAyMyBjZWxscyB0aGF0IGRvZXMgbm90IGFwcGVhciB0byBleHByZXNzIGFueSBvZiB0aGUgZmlicm9ibGFzdCwgQ0FGLCBwZXJpdmFzY3VsYXIsIG9yIGVuZG90aGVsaWFsIG1hcmtlcnMuIEFmdGVyIHBlcmZvcm1pbmcgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMsIHdlIGZpbmQgdGhhdCB0aGUgdG9wIDMgbWFya2VycyBmb3IgY2x1c3RlciA0IGFyZSBDTFUsIENENzQsIGFuZCBDUllBQi4gSW50ZXJlc3RpbmdseSwgQ0xVIGFuZCBDRDc0IHdlcmUgZm91bmQgdG8gYmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGluIHRoZSBhcENBRiBwb3B1bGF0aW9uIGRpc2NvdmVyZWQgaW4gdGhlIEtQQyBtb3VzZSBtb2RlbHMgb2YgQ0FGcyBpbiBFbHlhZGEgKmV0IGFsKi4KCmBgYHtyfQpEZWZhdWx0QXNzYXkoZmlicm8pIDwtICJTQ1QiCmZpYnJvX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoZmlicm8sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDEuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQpmaWJyb19tYXJrZXJzICU+JSAKICBmaWx0ZXIoY2x1c3RlciA9PSA0KSAlPiUgCiAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjbHVzdGVyLCBnZW5lLCBhdmdfbG9nMkZDLCBwX3ZhbF9hZGosIHBjdC4xLCBwY3QuMikgJT4lIAogIHNsaWNlX2hlYWQobiA9IDUpICU+JSAKICBrYmwoYm9va3RhYnMgPSBUUlVFLCBkaWdpdHMgPSA0LCByb3cubmFtZXMgPSBGQUxTRSkgJT4lIAogIGthYmxlX21pbmltYWwoImhvdmVyIiwgZnVsbF93aWR0aCA9IEZBTFNFKQpgYGAKCldlIHJlLXJ1biBHU0VBLCBhZ2FpbiB1c2luZyB0aGUgYFZBTWAgcGFja2FnZSBhbmQgdGhlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBmb3IgdGhlIGFwQ0FGIHBvcHVsYXRpb24gYXMgZGVmaW5lZCBpbiBFbHlhZGEgKmV0IGFsKiAod2l0aCB0aGUgbW91c2UgZ2VuZSBuYW1lcyBjb252ZXJ0ZWQgdG8gSEdOQyBzeW1ib2xzKS4gV2UgY2FuIHNlZSB0aGF0IHRoZSBhcENBRiBwYXRod2F5IGlzIHN0cm9uZ2x5IGVucmljaGVkIGluIGNsdXN0ZXIgNCBhcyBjb21wYXJlZCB0byB0aGUgb3RoZXIgQ0FGIGNsdXN0ZXJzLgoKYGBge3J9CmFwY2FmX2dlbmVzIDwtIGMoIkhMQS1EUUIxIiwgIkNENzQiLCAiU0FBM1AiLCAiU0xQSSIpCmdlbmVfc2V0cyA8LSBsaXN0KGljYWZfZ2VuZXMsIG15Y2FmX2dlbmVzLCBhcGNhZl9nZW5lcywgcGFuX2NhZl9nZW5lcykKbmFtZXMoZ2VuZV9zZXRzKSA8LSBjKCJpQ0FGIiwgIm15Q0FGIiwgImFwQ0FGIiwgIlBhbi1DQUYiKQpmb3IgKGkgaW4gc2VxKGdlbmVfc2V0cykpIHsKICBnZW5lX3NldHNbW2ldXSA8LSBnZW5lX3NldHNbW2ldXVtnZW5lX3NldHNbW2ldXSAlaW4lIHJvd25hbWVzKGZpYnJvKV0KfQpmaWJybyA8LSB2YW1Gb3JTZXVyYXQoZmlicm8sIAogICAgICAgICAgICAgICAgICAgICAgZ2VuZS5zZXQuY29sbGVjdGlvbiA9IGdlbmVfc2V0cywgCiAgICAgICAgICAgICAgICAgICAgICBnYW1tYSA9IFRSVUUpCkRlZmF1bHRBc3NheShmaWJybykgPC0gIlZBTWNkZiIKcDI1IDwtIEZlYXR1cmVQbG90KGZpYnJvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImFwQ0FGIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiYXBDQUYiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAyNSAvIHAyMApgYGAKCiMjIyBWaXN1YWxpemF0aW9uCgpGaW5hbGx5LCB3ZSBhZGQgY2VsbCBsYWJlbHMgdG8gb3VyIGlkZW50aWZpZWQgY2x1c3RlcnMuCgpgYGB7cn0KZmlicm8kbGFiZWwgPC0gY2FzZV93aGVuKGZpYnJvJHNldXJhdF9jbHVzdGVycyA9PSAwIH4gIm15Q0FGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWJybyRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJQZXJpdmFzY3VsYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpYnJvJHNldXJhdF9jbHVzdGVycyA9PSAyIH4gImlDQUYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpYnJvJHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIkVuZG90aGVsaWFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWJybyRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJhcENBRiIpCklkZW50cyhmaWJybykgPC0gImxhYmVsIgpwMjYgPC0gRGltUGxvdChmaWJybywgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDI2CmBgYAoKSGVyZSdzIHRoZSBtYXJrZXIgZ2VuZXMgZm9yIGVhY2ggY2x1c3Rlci4gCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0KRGVmYXVsdEFzc2F5KGZpYnJvKSA8LSAiU0NUIgpmaWJyb19tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2VycyhmaWJybywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkgJT4lIAogICAgICAgICAgICAgICAgICBtdXRhdGUoc291cmNlID0gIlN0cm9tYSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbG9nMmZjX2N1dG9mZiA9IDIpCnRvcDVfZmlicm9fbWFya2VycyA8LSBmaWJyb19tYXJrZXJzMiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnAyNyA8LSBEb3RQbG90KGZpYnJvLCBmZWF0dXJlcyA9IHRvcDVfZmlicm9fbWFya2VycyRnZW5lLCBkb3Quc2NhbGUgPSAxNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIpICsgCiAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gMTYsIHZqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImNlbnRlciIsIAogICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLCAKICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIGJhcmhlaWdodCA9IHVuaXQoMywgdW5pdHMgPSAiY20iKSwgdGl0bGUuaGp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDI3CmBgYAoKV2UnbGwgYWxzbyBjb21wdXRlIENBRi1vbmx5IG1hcmtlciBnZW5lcyAmIHZpc3VhbGl6ZSB0aGVtLiAKCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQpjYWYgPC0gc3Vic2V0KGZpYnJvLCBzdWJzZXQgPSBsYWJlbCAlaW4lIGMoImlDQUYiLCAibXlDQUYiLCAiYXBDQUYiKSkKY2FmX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoY2FmLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UgPSAiQ0FGIiwgCiAgICAgICAgICAgICAgICAgICAgICBsb2cyZmNfY3V0b2ZmID0gMikKdG9wNV9jYWZfbWFya2VycyA8LSBjYWZfbWFya2VycyAlPiUgCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhhdmdfbG9nMkZDKSkgJT4lIAogICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnAyOCA8LSBEb3RQbG90KGNhZiwgZmVhdHVyZXMgPSB0b3A1X2NhZl9tYXJrZXJzJGdlbmUsIGRvdC5zY2FsZSA9IDE1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIikgKyAKICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxNiwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksIAogICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgIHNpemUgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUpKQpwMjgKYGBgCgojIyBUIENlbGxzCgpHb2luZyBiYWNrIHRvIHRoZSBtYWluIGBTZXVyYXRgIG9iamVjdCwgd2Ugc2hvdWxkIGhhdmUgYSBsYXJnZSBwb3B1bGF0aW9uIG9mIFQgYW5kIE5LIGNlbGxzIHRoYXQgd2FycmFudHMgZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBVc2luZyBDRDNEIGV4cHJlc3Npb24gd2UgY2FuIGVhc2lseSBpZGVudGlmeSBjbHVzdGVycyAwLCAzLCBhbmQgNyBhcyB0aGUgbWl4ZWQgVCAmIE5LIGNlbGxzLiBXZSBhbHJlYWR5IHNlZSBzb21lIGdvb2Qgc2VwYXJhdGlvbiwgc28gcmVjbHVzdGVyaW5nIHRoZSBjZWxscyBzaG91bGQgaGF2ZSBnb29kIHJlc3VsdHMuIAoKYGBge3J9CnAyOSA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEM0QiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMjkgLyBwNApgYGAKCkhlcmUncyB0aGUgY2VsbHMgd2UnbGwgYmUgcmVjbHVzdGVyaW5nLiAKCmBgYHtyfQpua3RfY2VsbHMgPC0gcm93bmFtZXMocGRhY0BtZXRhLmRhdGFbcGRhY0BtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygwLCAzLCA4KSwgXSkKcDMwIDwtIERpbVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBjZWxscy5oaWdobGlnaHQgPSBua3RfY2VsbHMsIGNvbHMuaGlnaGxpZ2h0ID0gIm5hdnkiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKQpwMzAgLyBwNApgYGAKCiMjIyBUdW1vcgoKYGBge3J9Cm5rdF90dW1vciA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygwLCAzLCA4KSAmIGNvbmRpdGlvbiA9PSAiUERBQyIpCmBgYAoKIyMjIyBSZWNsdXN0ZXJpbmcKCkhlcmUgd2UgcnVuIGBSZWNsdXN0ZXJDZWxscygpYCwgd2hpbGUgdHJlYXRpbmcgdGhlIE5LICYgVCBjZWxsIGNsdXN0ZXJzIGFzIG9uZSBsYXJnZSBncm91cC4gVGhpcyB3aWxsIGhvcGVmdWxseSBhbGxvdyB1c2UgdG8gZWx1Y2lkYXRlIFQgY2VsbCBzdWJ0eXBlcy4gV2UgdXNlIGZld2VyIFBDcyBmb3IgdGhlc2UgY2VsbHMgc2luY2UgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gaW1tdW5lIGNlbGxzIGFyZSBzdWJ0bGUsIGFuZCBhZGRpbmcgbW9yZSBQQ3Mgd2lsbCBtb3N0IGxpa2VseSBvbmx5IGNvbnRyaWJ1dGUgbm9pc2UgdG8gb3VyIGFuYWx5c2VzLiAKCmBgYHtyfQpua3RfdHVtb3IgPC0gUmVjbHVzdGVyQ2VsbHMobmt0X3R1bW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gbGlzdCgwLCAzLCA4KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXJnZS5jbHVzdGVycyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5IVkcgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDMwLCA0MCwgNTAsIDYwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uLnZhbHMgPSBjKC4xLCAuMiwgLjMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZG8uZW1iZWRkaW5nID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKbmt0X3R1bW9yX3BjIDwtIEVtYmVkZGluZ3Mobmt0X3R1bW9yLCAicGNhIikKYGBgCgpPbmNlIGFnYWluIHdlJ2xsIHJ1biBGaXQtU05FIG9uIHRoZSByZWNsdXN0ZXJlZCBjZWxscy4gCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCm5rdF90dW1vcl9wYyA9IHIubmt0X3R1bW9yX3BjCiMgcnVuIEZpdC1TTkUKYWZmaW5fbmt0X3R1bW9yID0gUGVycGxleGl0eUJhc2VkTk4obmt0X3R1bW9yX3BjLCBwZXJwbGV4aXR5PTEwMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKG5rdF90dW1vcl9wYywgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZV9ua3RfdHVtb3IgPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX25rdF90dW1vciwgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9ua3RfdHVtb3IxID0gdHNuZV9ua3RfdHVtb3Iub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTQsIG1vbWVudHVtPTAuNikgCmVtYmVkX25rdF90dW1vcjIgPSBlbWJlZF9ua3RfdHVtb3IxLm9wdGltaXplKG5faXRlcj03NTAsIGV4YWdnZXJhdGlvbj0xLCBtb21lbnR1bT0wLjgpCmFmZmluX25rdF90dW1vci5zZXRfcGVycGxleGl0eSg1MCkKZW1iZWRfbmt0X3R1bW9yMyA9IGVtYmVkX25rdF90dW1vcjIub3B0aW1pemUobl9pdGVyPTUwMCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuNikKYGBgCgpUaGUgcmVlbWJlZGRpbmcgaXNuJ3QgcGVyZmVjdCwgd2hpY2ggd2Ugc29tZXdoYXQgZXhwZWN0ZWQgYXMgaW1tdW5lIGNlbGxzIGFyZSBkaWZmaWN1bHQgdG8gdGVsbCBhcGFydCBiYXNlZCBvbiB0aGUgdHJhbnNjcmlwdG9tZSBhbG9uZS4gCgpgYGB7cn0KZW1iZWRfbmt0X3R1bW9yIDwtIGFzLm1hdHJpeChweSRlbWJlZF9ua3RfdHVtb3IzKQpyb3duYW1lcyhlbWJlZF9ua3RfdHVtb3IpIDwtIGNvbG5hbWVzKG5rdF90dW1vcikKbmt0X3R1bW9yQHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBua3RfdHVtb3JAcmVkdWN0aW9ucyR0c25lCm5rdF90dW1vckByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfbmt0X3R1bW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbCA9IFRSVUUpCnAzMSA8LSBEaW1QbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6Y2F0ZWdvcnkyMF9kMyIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDMxCmBgYAoKIyMjIyBDZWxsIFR5cGUgSWRlbnRpZmljYXRpb24KCiMjIyMjIENENCsgVAoKQ2x1c3RlcnMgMCBhbmQgMSBjb250YWluIG91ciBDRDQrIFQgY2VsbHMsIHdoaWNoIHdlIGNoYXJhY3Rlcml6ZSB1c2luZyBJTDdSIGFzIHdlIGRpZCBpbiB0aGUgUEJNQzNrIHZpZ25ldHRlLiBJdCdzIHNvbWV3aGF0IG91dHNpZGUgb2Ygb3VyIHNjb3BlIGhlcmUgdG8gZGV0ZXJtaW5lIHdoaWNoIHN1YnR5cGUgZWFjaCBjbHVzdGVyIGJlbG9uZ3MgdG8sIHNvIHdlJ2xsIHNpbXBseSBhc3NpZ24gYm90aCBjbHVzdGVycyB0aGUgc2FtZSBsYWJlbCBhbmQgbW92ZSBvbi4gCgpgYGB7cn0KcDMyIDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJJTDdSIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDMzIDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDY5IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAzMiB8IHAzMykgLyBwMzEKYGBgCgojIyMjIyBULXJlZ3MKCkNsdXN0ZXIgMyBjb250YWlucyB0aGUgcmVndWxhdG9yeSBUIGNlbGxzLiAKCmBgYHtyfQpwMzQgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIklMMlJBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDM1IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJGT1hQMyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMzQgfCBwMzUpIC8gcDMxCmBgYAoKIyMjIyMgUHJvbGlmZXJhdGluZyBULXJlZ3MKCldlIGNhbiBmaW5kIHRoZSBwcm9saWZlcmF0aW5nIFQtcmVncyBpbiBjbHVzdGVyIDcuIAoKYGBge3J9CnAzNiA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiVE9QMkEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMzYgLyBwMzEKYGBgCgojIyMjIyBNYXN0CgpNYXN0IGNlbGxzIGNhbiBiZSBpZGVudGlmaWVkIHVzaW5nIFRQU0FCMSBleHByZXNzaW9uIGluIGNsdXN0ZXIgNi4gCgpgYGB7cn0KcDM3IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJUUFNBQjEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMzcgLyBwMzEKYGBgCgojIyMjIyBOSwoKTktHNyBhbmQgUFJGMSBzaG93IHVzIHRoZSBOSyBjZWxscyBpbiBjbHVzdGVyIDUuIAoKYGBge3J9CnAzOCA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTktHNyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAzOSA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUFJGMSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMzggfCBwMzkpIC8gcDMxCmBgYAoKIyMjIyMgQ0Q4KyBUCgpXZSB1c2UgQ0Q4QSBhbmQgQ0QyIHRvIHJldmVhbCB0aGUgQ0Q4KyBUIGNlbGxzIHdpdGhpbiBjbHVzdGVycyAyIGFuZCA0LiAKCmBgYHtyfQpwNDAgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEOEEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNDEgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEMiIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNDAgfCBwNDEpIC8gcDMxCmBgYAoKIyMjIyBJbnRlcm1lZGlhdGUgTW9ub2N5dGUKCkxhc3RseSwgd2UgaGF2ZSBjbHVzdGVyIDgsIHdoaWNoIGRvZXNuJ3QgaGlnaGx5IGV4cHJlc3Mgb3VyIHBhbi1UL05LIGNlbGwgbWFya2VycyBDRDNEIGFuZCBDRDIuIEl0IGNvdWxkIGJlIGEgbXllbG9pZCBjZWxsIGNsdXN0ZXIgdGhhdCB3YXMgbWlzdGFrZW5seSBncm91cGVkIHdpdGggdGhlIFQvTksgY2VsbHMuIFdlJ2xsIHN0YXJ0IHdpdGggYSBXaWxjb3hvbiB0ZXN0IHRvIGRldGVybWluZSBpdHMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLiBJbnRlcmVzdGluZ2x5LCBzZXZlcmFsIFtpbnRlcm1lZGlhdGUgbW9ub2N5dGUgbWFya2Vyc10oaHR0cHM6Ly93d3cuZnJvbnRpZXJzaW4ub3JnL2FydGljbGVzLzEwLjMzODkvZmltbXUuMjAxOS4wMjAzNS9mdWxsI0IzKSAtIExZWiwgSExBLURSQSwgQ0Q3NCwgYW5kIEhMQS1EUEIxIC0gYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBpbiBjbHVzdGVyIDguIAoKYGBge3J9CmNsdXN0OF9tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKG5rdF90dW1vciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5kaWZmLnBjdCA9IC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KSAlPiUgCiAgICAgICAgICAgICAgICAgIGZpbHRlcihjbHVzdGVyID09IDgsIHBfdmFsX2FkaiA8IC4wNSkgJT4lIAogICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoMSAtIHBfdmFsX2FkaikpCmNsdXN0OF9tYXJrZXJzICU+JSAKICBmaWx0ZXIoZ2VuZSAlaW4lIGMoIkxZWiIsICJITEEtRFJBIiwgIkNENzQiLCAiSExBLURQQjEiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoY2x1c3RlciwgZ2VuZSwgYXZnX2xvZzJGQywgcF92YWxfYWRqLCBwY3QuMSwgcGN0LjIpICU+JSAKICBrYmwoYm9va3RhYnMgPSBUUlVFLCBkaWdpdHMgPSA0LCByb3cubmFtZXMgPSBGQUxTRSkgJT4lIAogIGthYmxlX21pbmltYWwoImhvdmVyIiwgZnVsbF93aWR0aCA9IEZBTFNFKQpgYGAKCldlJ2xsIHBsb3Qgc29tZSBvZiB0aG9zZSBtYXJrZXJzIGJlbG93LiAKCmBgYHtyfQpwNDIgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkxZWiIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA0MyA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSExBLURSQSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA0NCA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0Q3NCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA0NSA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSExBLURQQjEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQooKHA0MiB8IHA0MykgLyAocDQ0IHwgcDQ1KSkgLyBwMzEKYGBgCgojIyMjIFZpc3VhbGl6YXRpb24KCldlIGFkZCBsYWJlbHMgdG8gb3VyIFQgY2VsbCBgU2V1cmF0YCBvYmplY3QgYW5kIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4gCgpgYGB7cn0Kbmt0X3R1bW9yJGxhYmVsIDwtIGNhc2Vfd2hlbihua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDAgfiAiQ0Q0KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSAxIH4gIkNENCsgVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJDRDgrIFQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiVC1yZWciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDQgfiAiQ0Q4KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSA1IH4gIk5LIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIk1hc3QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDcgfiAiUHJvbGlmZXJhdGluZyBULXJlZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gOCB+ICJJbnRlcm1lZGlhdGUgTW9ub2N5dGUiKQpJZGVudHMobmt0X3R1bW9yKSA8LSAibGFiZWwiCnA0NiA8LSBEaW1QbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNDYKYGBgCgpIZXJlJ3MgdGhlIG1hcmtlciBnZW5lcy4gCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0Kbmt0X3R1bW9yX21hcmtlcnMyIDwtIEZpbmRBbGxNYXJrZXJzKG5rdF90dW1vciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAuNzUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoc291cmNlID0gIk5LL1QgVHVtb3IiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyZmNfY3V0b2ZmID0gLjc1KQp0b3A1X25rdF90dW1vcl9tYXJrZXJzIDwtIG5rdF90dW1vcl9tYXJrZXJzMiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhhdmdfbG9nMkZDKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnA0NyA8LSBEb3RQbG90KG5rdF90dW1vciwgZmVhdHVyZXMgPSB1bmlxdWUodG9wNV9ua3RfdHVtb3JfbWFya2VycyRnZW5lKSwgZG90LnNjYWxlID0gMTUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gcGFsZXR0ZWVyX2QoIndlc2FuZGVyc29uOjpaaXNzb3UxIikpICsKICAgICAgIGxhYnMoY29sb3IgPSAiRXhwcmVzc2lvbiIsIHNpemUgPSAiJSBFeHByZXNzZWQiKSArIAogICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDE2LCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgCiAgICAgICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLCAKICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgCiAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCBiYXJoZWlnaHQgPSB1bml0KDMsIHVuaXRzID0gImNtIiksIHRpdGxlLmhqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnA0NwpgYGAKCiMjIyBBZGphY2VudCBOb3JtYWwKCmBgYHtyfQpua3Rfbm9ybSA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygwLCAzLCA4KSAmIGNvbmRpdGlvbiA9PSAiQWRqTm9ybSIpCmBgYAoKIyMjIyBSZWNsdXN0ZXJpbmcKCmBgYHtyfQpua3Rfbm9ybSA8LSBSZWNsdXN0ZXJDZWxscyhua3Rfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gbGlzdCgwLCAzLCA4KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uSFZHID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGsudmFscyA9IGMoMTUsIDIwLCAyNSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uLnZhbHMgPSBjKC4yLCAuMywgLjQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm4ubWV0cmljID0gImV1Y2xpZGVhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKbmt0X25vcm1fcGMgPC0gRW1iZWRkaW5ncyhua3Rfbm9ybSwgInBjYSIpCmBgYAoKQXMgd2l0aCB0aGUgb3RoZXIgcmVjbHVzdGVyaW5ncywgd2UnbGwgcnVuIEZpdC1TTkUgaW4gb3JkZXIgdG8gKGhvcGVmdWxseSkgb2J0YWluIGEgYmV0dGVyIGxvdy1kaW1lbnNpb25hbCBlbWJlZGRpbmcgb2Ygb3VyIGNlbGxzLgoKYGBge3B5dGhvbn0KIyBpbXBvcnQgZGF0YQpua3Rfbm9ybV9wYyA9IHIubmt0X25vcm1fcGMKIyBydW4gRml0LVNORQphZmZpbl9ua3Rfbm9ybSA9IFBlcnBsZXhpdHlCYXNlZE5OKG5rdF9ub3JtX3BjLCBwZXJwbGV4aXR5PTMwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2Eobmt0X25vcm1fcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfbmt0X25vcm0gPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX25rdF9ub3JtLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkX25rdF9ub3JtMSA9IHRzbmVfbmt0X25vcm0ub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTEyLCBtb21lbnR1bT0wLjYpIAplbWJlZF9ua3Rfbm9ybTIgPSBlbWJlZF9ua3Rfbm9ybTEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpgYGB7cn0KZW1iZWRfbmt0X25vcm0gPC0gYXMubWF0cml4KHB5JGVtYmVkX25rdF9ub3JtMikKcm93bmFtZXMoZW1iZWRfbmt0X25vcm0pIDwtIGNvbG5hbWVzKG5rdF9ub3JtKQpua3Rfbm9ybUByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gbmt0X25vcm1AcmVkdWN0aW9ucyR0c25lCm5rdF9ub3JtQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9ua3Rfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwNDggPC0gRGltUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNDgKYGBgCgojIyMjIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKRmlyc3Qgd2UnbGwgdXNlIGEgV2lsY294b24gdGVzdCB0byBkZXRlcm1pbmUgd2hpY2ggZ2VuZXMgY2hhcmFjdGVyaXplIGVhY2ggY2x1c3Rlci4gCgpgYGB7cn0Kbmt0X25vcm1fbWFya2VycyA8LSBGaW5kQWxsTWFya2Vycyhua3Rfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5kaWZmLnBjdCA9IC4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpICU+JSAKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KQpua3Rfbm9ybV9tYXJrZXJzICAlPiUgCiAgZHBseXI6OnNlbGVjdChjbHVzdGVyLCBnZW5lLCBhdmdfbG9nMkZDLCBwX3ZhbF9hZGosIHBjdC4xLCBwY3QuMikgJT4lIAogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICB0b3BfbihuID0gMywgd3QgPSBhdmdfbG9nMkZDKSAlPiUgCiAga2JsKGJvb2t0YWJzID0gVFJVRSwgZGlnaXRzID0gNCkgJT4lIAogIGthYmxlX21pbmltYWwoImhvdmVyIiwgZnVsbF93aWR0aCA9IEZBTFNFKQpgYGAKCiMjIyMjIENENCsgVAoKV2UgY2FuIHVzZSBJTDdSIGFuZCBTMTAwQTQgZXhwcmVzc2lvbiB0byBpZGVudGlmeSB0aGUgbWVtb3J5IENENCsgVCBjZWxscyBpbiBjbHVzdGVycyAwICYgMi4gSUw3UiBhbmQgQ0NSNyBpZGVudGlmeSB0aGUgbmFpdmUgQ0Q0KyBUIGNlbGxzIGluIHRoZSBhZGphY2VudCBjbHVzdGVyIDYuIAoKYGBge3J9CnA0OSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJJTDdSIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDUwIDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA1MSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDQ1I3IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA0OSB8IHA1MCB8IHA1MSkgLyBwNDgKYGBgCgojIyMjIyBDRDgrIFQKCk5leHQgd2UgcmV2ZWFsIHRoZSBDRDgrIFQgY2VsbHMgaW4gY2x1c3RlcnMgMSBhbmQgMyB3aXRoIENEOEEsIGFzIHBlciB1c3VhbC4gCgpgYGB7cn0KcDUyIDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEOEEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNTIgLyBwNDgKYGBgCgojIyMjIyBULXJlZwoKVGhlIFQtcmVnIGNsdXN0ZXIsIGNsdXN0ZXIgNSwgaXMgaWRlbnRpZmllZCB1c2luZyBUSUdJVCBhbmQgRk9YUDMuIAoKYGBge3J9CnA1MyA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJUSUdJVCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA1NCA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJGT1hQMyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNTMgfCBwNTQpIC8gcDQ4CmBgYAoKIyMjIyMgTksKClRoZSBuYXR1cmFsIGtpbGxlcnMgY2FuIGJlIGZvdW5kIGluIGNsdXN0ZXIgNCB0aHJvdWdoIHRoZWlyIGV4cHJlc3Npb24gb2YgUFJGMSBhbmQgTktHNy4gVGhlIE5LRzcgZXhwcmVzc2lvbiBhbHNvIGNvbmZpcm1zIHRoZSBpZGVudGl0aWVzIG9mIHRoZSBDRDgrIFQgY2VsbHMgd2UganVzdCBhbm5vdGF0ZWQuIAoKYGBge3J9CnA1NSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJQUkYxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDU2IDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIk5LRzciLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDU1IHwgcDU2KSAvIHA0OApgYGAKCiMjIyMjIFByb2xpZmVyYXRpbmcgVC1yZWcKClRoZSB0aW55IHByb2xpZmVyYXRpbmcgVC1yZWcgcG9wdWxhdGlvbiBpbiBjbHVzdGVyIDcgaXMgY2hhcmFjdGVyaXplZCBieSBUT1AyQS4gCgpgYGB7cn0KcDU3IDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlRPUDJBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDU3IC8gcDQ4CmBgYAoKIyMjIyBWaXN1YWxpemF0aW9uCgpXZSBhZGQgZmluYWwgY2VsbCBsYWJlbHMgdG8gb3VyIDggY2VsbCBjbHVzdGVycy4gCgpgYGB7cn0Kbmt0X25vcm0kbGFiZWwgPC0gY2FzZV93aGVuKG5rdF9ub3JtJHNldXJhdF9jbHVzdGVycyA9PSAwIH4gIk1lbW9yeSBDRDQrIFQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF9ub3JtJHNldXJhdF9jbHVzdGVycyA9PSAxIH4gIkNEOCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJNZW1vcnkgQ0Q0KyBUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF9ub3JtJHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIkNEOCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJOSyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gNSB+ICJULXJlZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDYgfiAiTmFpdmUgQ0Q0KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gNyB+ICJQcm9saWZlcmF0aW5nIFQtcmVnIikKSWRlbnRzKG5rdF9ub3JtKSA8LSAibGFiZWwiCnA1OCA8LSBEaW1QbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNTgKYGBgCgpIZXJlJ3MgdGhlIG1hcmtlciBnZW5lcy4gCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0Kbmt0X25vcm1fbWFya2VyczIgPC0gRmluZEFsbE1hcmtlcnMobmt0X25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAuNzUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UgPSAiTksvVCBBZGphY2VudCBOb3JtYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyZmNfY3V0b2ZmID0gLjc1KQp0b3A1X25rdF9ub3JtX21hcmtlcnMgPC0gbmt0X25vcm1fbWFya2VyczIlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnA1OSA8LSBEb3RQbG90KG5rdF9ub3JtLCBmZWF0dXJlcyA9IHVuaXF1ZSh0b3A1X25rdF9ub3JtX21hcmtlcnMkZ2VuZSksIGRvdC5zY2FsZSA9IDE1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIikgKyAKICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxNiwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksIAogICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgIHNpemUgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUpKQpwNTkKYGBgCgojIyBEdWN0YWwgQ2VsbHMKCiMjIyBSZWNsdXN0ZXJpbmcKCldlIHVzZSBLUlQ4IGV4cHJlc3Npb24gdG8gc2hvdyB0aGUgZHVjdGFsIGNlbGxzIHJlc2lkaW5nIGluIGNsdXN0ZXJzIDUgYW5kIDkuIFdlIG5vdGUgdGhhdCBzb21lIHJlZ2lvbnMgb2YgY2x1c3RlcnMgNSBhbmQgOSBoYXZlIG5vIEtSVDggZXhwcmVzc2lvbiwgd2hpY2ggbGlrZWx5IG1lYW5zIHRoYXQgdGhleSBhcmUgY29tcG9zZWQgb2YgZGlmZmVyZW50IGNlbGwgdHlwZXMuIAoKYGBge3J9CnA2MCA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIktSVDgiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDYwIC8gcDQKYGBgCgpUaGVzZSBhcmUgdGhlIGNlbGxzIHdlJ2xsIGJlIHJlY2x1c3RlcmluZy4gCgpgYGB7cn0KZHVjdGFsX2NlbGxzIDwtIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhW3BkYWNAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyAlaW4lIGMoNSwgOSksIF0pCnA2MSA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgY2VsbHMuaGlnaGxpZ2h0ID0gZHVjdGFsX2NlbGxzLCBjb2xzLmhpZ2hsaWdodCA9ICJuYXZ5IiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDYxIC8gcDQKYGBgCgoKV2UgcnVuIGBTQ0lTU09SU2AsIHRoZW4gdXNlIGEgV2lsY294b24gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gdGVzdCB0byBkZXRlcm1pbmUgcG90ZW50aWFsIG1hcmtlcnMgZm9yIGVhY2ggY2x1c3Rlci4gCgpgYGB7cn0KZHVjdGFsIDwtIFJlY2x1c3RlckNlbGxzKHBkYWMsIAogICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guY2x1c3QgPSBsaXN0KDUsIDkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuLkhWRyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDIwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGsudmFscyA9IGMoMjAsIDMwLCA0MCwgNTApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5uLm1ldHJpYyA9ICJldWNsaWRlYW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjIsIC4zLCAuNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpkdWN0YWwkY2x1c3Rlcl9jb2xvciA8LSBjYXNlX3doZW4oZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSAwIH4gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIilbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDIgfiBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSAzIH4gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKVs0XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIilbNV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDUgfiBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpWzZdKQpkdWN0YWxfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhkdWN0YWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5kaWZmLnBjdCA9IC4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpICU+JSAKICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkKZHVjdGFsX21hcmtlcnMgJT4lIAogIGRwbHlyOjpzZWxlY3QoY2x1c3RlciwgZ2VuZSwgYXZnX2xvZzJGQywgcF92YWxfYWRqLCBwY3QuMSwgcGN0LjIpICU+JSAKICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgdG9wX24obiA9IDMsIHd0ID0gYXZnX2xvZzJGQykgJT4lIAogIGtibChib29rdGFicyA9IFRSVUUsIGRpZ2l0cyA9IDQpICU+JSAKICBrYWJsZV9taW5pbWFsKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgpBZ2Fpbiwgd2UnbGwgcnVuIEZpdC1TTkUgb24gdGhlIHJlY2x1c3RlcmVkIGNlbGxzLiAKCmBgYHtyfQpkdWN0X3BjIDwtIEVtYmVkZGluZ3MoZHVjdGFsLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCmR1Y3RfcGMgPSByLmR1Y3RfcGMKIyBydW4gRml0LVNORQphZmZpbl9kdWN0ID0gUGVycGxleGl0eUJhc2VkTk4oZHVjdF9wYywgcGVycGxleGl0eT0zMCwgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShkdWN0X3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX2R1Y3QgPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX2R1Y3QsIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWRfZDEgPSB0c25lX2R1Y3Qub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTEwLCBtb21lbnR1bT0wLjYpCmVtYmVkX2QyID0gZW1iZWRfZDEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpXZSBwdWxsIHRoZSByZXN1bHRzIGludG8gUiwgbWFraW5nIHN1cmUgdG8gc2F2ZSB0aGUgQmFybmVzLUh1dCB0LVNORSByZXN1bHRzIGluIGFub3RoZXIgcmVkdWN0aW9uIHNsb3QuCgpgYGB7cn0KZW1iZWRfZHVjdCA8LSBhcy5tYXRyaXgocHkkZW1iZWRfZDIpCnJvd25hbWVzKGVtYmVkX2R1Y3QpIDwtIGNvbG5hbWVzKGR1Y3RhbCkKZHVjdGFsQHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBkdWN0YWxAcmVkdWN0aW9ucyR0c25lCmR1Y3RhbEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZHVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiRml0U05FXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwNjIgPC0gRGltUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDYyCmBgYAoKV2UnbGwgYWxzbyBydW4gYFZBTWAsIHVzaW5nIHRoZSBZZWggTGFiJ3MgZ2VuZSBzZXRzIGZvciBiYXNhbCBhbmQgY2xhc3NpY2FsIFBEQUMuIAoKYGBge3J9CnBkYWNfZ2VuZV9zZXRzIDwtIGxpc3QoY2xhc3NpY2FsX2dlbmVzLCBiYXNhbF9nZW5lcykKbmFtZXMocGRhY19nZW5lX3NldHMpIDwtIGMoIkNsYXNzaWNhbCBQREFDIiwgIkJhc2FsLWxpa2UgUERBQyIpCmZvciAoaSBpbiBzZXEocGRhY19nZW5lX3NldHMpKSB7CiAgcGRhY19nZW5lX3NldHNbW2ldXSA8LSBwZGFjX2dlbmVfc2V0c1tbaV1dW3BkYWNfZ2VuZV9zZXRzW1tpXV0gJWluJSByb3duYW1lcyhkdWN0YWwpXQp9CmR1Y3RhbCA8LSB2YW1Gb3JTZXVyYXQoZHVjdGFsLCAKICAgICAgICAgICAgICAgICAgICAgICBnZW5lLnNldC5jb2xsZWN0aW9uID0gcGRhY19nZW5lX3NldHMsIAogICAgICAgICAgICAgICAgICAgICAgIGdhbW1hID0gVFJVRSkKRGVmYXVsdEFzc2F5KGR1Y3RhbCkgPC0gIlZBTWNkZiIKYGBgCgpFeGFtaW5pbmcgdGhlIGBWQU1gIHJlc3VsdHMsIHdlIHNlZSB0aGF0IGNsdXN0ZXJzIDAgJiAxIGFyZSBlbnJpY2hlZCBmb3IgQ2xhc3NpY2FsIFBEQUMsIGFuZCBjbHVzdGVyIDQgaGFzIHZlcnkgaGlnaCBCYXNhbCBQREFDIHNjb3Jlcy4gCgpgYGB7cn0KcDYzIDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDbGFzc2ljYWwgUERBQyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA2NCA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQmFzYWwtbGlrZSBQREFDIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA2MyB8IHA2NCkgLyBwNjIKYGBgCgojIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uIAoKIyMjIyBMaXBpZCBQcm9jZXNzaW5nCgpXZSB1c2UgQU5QRVAgJiBGQUJQMSBleHByZXNzaW9uIHRvIGlkZW50aWZ5IHRoZSBsaXBpZCBwcm9jZXNzaW5nIGR1Y3RhbCBjZWxscyBpbiBjbHVzdGVyIDYuIAoKYGBge3J9CkRlZmF1bHRBc3NheShkdWN0YWwpIDwtICJTQ1QiCnA2NSA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQU5QRVAiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNjYgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkZBQlAxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA2NSB8IHA2NikgLyBwNjIKYGBgCgojIyMjIFNlY3JldG9yeQoKRXhwcmVzc2lvbiBvZiBTT0QzIGFuZCBDRlRSIHJldmVhbHMgdGhlIHNlY3JldG9yeSBjZWxscyBpbiBjbHVzdGVyIDMuCgpgYGB7cn0KcDY3IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTT0QzIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDY4IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRlRSIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA2NyB8IHA2OCkgLyBwNjIKYGBgCgojIyMjIENsYXNzaWNhbCAxCgpXZSB1c2UgVEZGMSBhbmQgVEZGMiBleHByZXNzaW9uIHRvIGFubm90YXRlIHRoZSBjbGFzc2ljYWwgMSBlcGl0aGVsaWFsIGNlbGxzIGluIGNsdXN0ZXJzIDAgYW5kIDEuIFdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSB0d28gY2xhc3NpY2FsIDEgY2x1c3RlcnMgYXJlIHNwbGl0IGJ5IHRoZSBzYW1wbGUgZnJvbSB3aGljaCB0aGUgY2VsbHMgb3JpZ2luYXRlLiBHb2luZyBmb3J3YXJkLCB3ZSdsbCBzaW1wbHkgbGFiZWwgYm90aCBjbHVzdGVycyBhcyBjbGFzc2ljYWwgMS4gCgpgYGB7cn0KcDY5IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJURkYxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDcwIDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJURkYyIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDcxIDwtIERpbVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gInNhbXBsZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTYW1wbGUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNjkgfCBwNzAgfCBwNzEpIC8gcDYyCmBgYAoKIyMjIyBDbGFzc2ljYWwgMgoKVGhlIGNsYXNzaWNhbCAyIGNlbGxzIGFyZSBsb2NhdGVkIGluIGNsdXN0ZXIgNiwgYXMgZXZpZGVuY2VkIGJ5IHRoZWlyIGV4cHJlc3Npb24gb2YgQ1JJU1AzLiBXZSBhbHNvIHNlZSB0aGF0IEdBVEE2LCBhIGNhbm9uaWNhbCBjbGFzc2ljYWwgUERBQyBtYXJrZXIsIGlzIGV4cHJlc3NlZCBpbiBib3RoIGNsYXNzaWNhbCBjbHVzdGVycywgYnV0IG5vdCBpbiB0aGUgcHV0YXRpdmUgYmFzYWwgY2x1c3Rlci4gCgpgYGB7cn0KcDcyIDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDUklTUDMiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNzMgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkdBVEE2IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA3MiB8IHA3MykgLyBwNjIKYGBgCgojIyMjIEJhc2FsCgpUaGUgYmFzYWwgY29tcGFydG1lbnQgd2VpZ2h0cyBmcm9tIGBERUNPREVSYCBhcmUgaGlnaGVzdCBpbiBjbHVzdGVyIDQsIHdoaWNoIHdlIHdpbGwgZGVub3RlIGFzIGJlaW5nIGNvbXBvc2VkIG9mIGJhc2FsLWxpa2UgUERBQy4gCgpgYGB7cn0KcDc0IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJiYXNhbCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJCYXNhbCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDc1IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJjbGFzc2ljYWwiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQ2xhc3NpY2FsIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNzYgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImJjX3JhdGlvIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkJhc2FsOkNsYXNzaWNhbCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDc3IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJtYWxpZyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlppc3NvdTEiLCBuID0gNSlbYyg1LCAyKV0pICArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiTWFsaWduYW50IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDc0IHwgcDc1IHwgcDc2IHwgcDc3KSAvIHA2MgpgYGAKCiMjIyMgQWNpbmFyCgpMYXN0bHksIHdlIHNob3cgdGhhdCBjbHVzdGVyIDIgaXMgY29tcG9zZWQgb2YgYWNpbmFyIGNlbGxzIHVzaW5nIENUUkIyLgoKYGBge3J9CnA3OCA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ1RSQjIiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNzggLyBwNjIKYGBgCgojIyMgVmlzdWFsaXphdGlvbgoKV2UgYWRkIGZpbmFsIGNsdXN0ZXIgbGFiZWxzIHRvIG91ciBgU2V1cmF0YCBvYmplY3QgYW5kIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4KCmBgYHtyfQpkdWN0YWwkbGFiZWwgPC0gY2FzZV93aGVuKGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJDbGFzc2ljYWwgMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJDbGFzc2ljYWwgMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJBY2luYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiU2VjcmV0b3J5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA0IH4gIkJhc2FsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA1IH4gIkxpcGlkIFByb2MuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIkNsYXNzaWNhbCAyIikKSWRlbnRzKGR1Y3RhbCkgPC0gImxhYmVsIgpwNzkgPC0gRGltUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIixwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDc5CmBgYAoKVGhlIEJhc2FsIGNsdXN0ZXIsIGFsb25nIHdpdGggdGhlIENsYXNzaWNhbCAyIGNsdXN0ZXIsIHNob3dzIGEgaGlnaCBwZXJjZW50YWdlIG9mIG1hbGlnbmFudCBjZWxscyBhcyBpZGVudGlmaWVkIGJ5IGBDT05JQ1NtYXRgLiAKCmBgYHtyfQpkdWN0YWxAbWV0YS5kYXRhICU+JSAKICBtdXRhdGUobWFsaWcyID0gY2FzZV93aGVuKG1hbGlnID09ICJNYWxpZ25hbnQiIH4gMSwgVFJVRSB+IDApKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWwpICU+JSAKICBzdW1tYXJpc2UoTSA9IG1lYW4obWFsaWcyKSkgJT4lIAogIG11dGF0ZShNID0gZm9ybWF0dGFibGU6OnBlcmNlbnQoTSwgZGlnaXRzID0gMikpICU+JSAKICBrYmwoYm9va3RhYnMgPSBUUlVFLCBjb2wubmFtZXMgPSBjKCJDZWxsdHlwZSIsICJNZWFuICUgTWFsaWduYW50IikpICU+JSAKICBrYWJsZV9taW5pbWFsKGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgpIZXJlJ3MgdGhlIG1hcmtlciBnZW5lcy4gCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0KZHVjdGFsX21hcmtlcnMyIDwtIEZpbmRBbGxNYXJrZXJzKGR1Y3RhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkgJT4lIAogICAgICAgICAgICAgICAgICAgbXV0YXRlKHNvdXJjZSA9ICJEdWN0YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyZmNfY3V0b2ZmID0gMikKdG9wNV9kdWN0YWxfbWFya2VycyA8LSBkdWN0YWxfbWFya2VyczIgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBzbGljZV9oZWFkKG4gPSA1KQpwODAgPC0gRG90UGxvdChkdWN0YWwsIGZlYXR1cmVzID0gdW5pcXVlKHRvcDVfZHVjdGFsX21hcmtlcnMkZ2VuZSksIGRvdC5zY2FsZSA9IDE1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIikgKyAKICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxNiwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksIAogICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgIHNpemUgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUpKQpwODAKYGBgCgojIyBQbGFzbWEgQ2VsbHMgJiBQbGFzbWFjeXRvaWQgRENzCgpXZSB1c2UgSkNIQUlOIChkZW5vdGVkIElHSiBpbiBFbHlhZGEgKmV0IGFsKikgdG8gcmV2ZWFsIHRoZSBQbGFzbWEgY2VsbHMgaW4gY2x1c3RlciAxMCwgYW5kIElSRjcgdG8gaWRlbnRpZnkgdGhlIHBsYXNtYWN5dG9pZCBEQ3MgaW4gY2x1c3RlciAxMS4gCgpgYGB7cn0KcDgxIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSkNIQUlOIiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJKQ0hBSU4gKElHSikiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA4MiA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIklSRjciLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIklSRjciKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwODEgfCBwODIpIC8gcDQKYGBgCgojIyBCIENlbGxzCgpXZSBjYW4gaWRlbnRpZnkgdGhlIEIgY2VsbHMgaW4gY2x1c3RlciA0IHVzaW5nIGpvaW50IGV4cHJlc3Npb24gb2YgTVM0QTEgYW5kIENENzlBLiBUaGUgY2x1c3RlciBpcyBzcGxpdCBpbnRvIHR3byBzdWJjbHVzdGVycyBieSB0aXNzdWUgdHlwZTogYWRqYWNlbnQgbm9ybWFsIGFuZCBQREFDLiBXaGlsZSBpdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBkZXRlcm1pbmUgdGhlIGdlbmV0aWMgZHJpdmVycyBvZiB0aGF0IHNlcGFyYXRpb24sIGl0J3Mgc29tZXdoYXQgb3V0c2lkZSBvZiBvdXIgc2NvcGUgaGVyZS4gCgpgYGB7cn0KcDgzIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTVM0QTEiLCBwdC5zaXplID0gMC43NSkgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiTVM0QTEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA4NCA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNENzlBIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkNENzlBIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwODUgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gImNvbmRpdGlvbiIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiVGlzc3VlIFR5cGUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwODMgfCBwODQgfCBwODUpIC8gcDQKYGBgCgojIyBNeWVsb2lkIENlbGxzCgpMYXN0bHksIHdlJ2xsIHNwbGl0IHVwIHRoZSBteWVsb2lkIHBvcHVsYXRpb24gYnkgdGlzc3VlIGNvbmRpdGlvbiAoUERBQyB2cy4gYWRqYWNlbnQgbm9ybWFsKSBqdXN0IGxpa2Ugd2UgZGlkIHdpdGggdGhlIE5LIC8gVCBjZWxscy4gV2UnbGwgcnVuIGBTQ0lTU09SU2AsIGFubm90YXRlIHRoZSBjbHVzdGVycywgYW5kIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4gCgpIZXJlJ3MgdGhlIGNlbGxzIHdlJ2xsIGJlIHJlY2x1c3RlcmluZy4gCgpgYGB7cn0KbXllbG9pZF9jZWxscyA8LSByb3duYW1lcyhwZGFjQG1ldGEuZGF0YVtwZGFjQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDEsIDIsIDcpLCBdKQpwODYgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGNlbGxzLmhpZ2hsaWdodCA9IG15ZWxvaWRfY2VsbHMsIGNvbHMuaGlnaGxpZ2h0ID0gIm5hdnkiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKQpwODYgLyBwNApgYGAKCiMjIyBUdW1vciAKCkZpcnN0IHdlJ2xsIGF0dGVtcHQgdG8gYXNzaWduIGJyb2FkIGNlbGwgdHlwZSBsYWJlbHMgdG8gZWFjaCBvZiB0aGUgZm91ciBwdXRhdGl2ZSBteWVsb2lkIGNsdXN0ZXJzLiBXZSdsbCB1c2UgdGhlIG1hcmtlciBnZW5lcyBmcm9tIEVseWFkYSAqZXQgYWwqIG9uY2UgYWdhaW4uIAoKYGBge3J9Cm15b190dW1vciA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygxLCAyLCA3KSAmIGNvbmRpdGlvbiA9PSAiUERBQyIpCnA4NyA8LSBEaW1QbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDg3CmBgYAoKQ2x1c3RlciAxIGFwcGVhcnMgdG8gYmUgY29tcG9zZWQgb2Ygb3VyIHJlc2lkZW50ICYgYWx0ZXJuYXRpdmVseSBhY3RpdmF0ZWQgbWFjcm9waGFnZXMgZHVlIHRvIGl0cyBleHByZXNzaW9uIG9mIENEMTQgJiBDMVFBIGFuZCBTUFAxLCByZXNwZWN0aXZlbHkuIAoKYGBge3J9CnA4OCA8LSBGZWF0dXJlUGxvdChteW9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDE0IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwODkgPC0gRmVhdHVyZVBsb3QobXlvX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkMxUUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQzFRQSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDkwIDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTUFAxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNQUDEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwODggfCBwODkgfCBwOTApIC8gcDg3CmBgYAoKV2UgY2FuIHVzZSBMWVogYW5kIFMxMDBBOCBleHByZXNzaW9uIHRvIHJldmVhbCB0aGUgY2xhc3NpYyBtb25vY3l0ZXMgYW5kIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgMi4gCgpgYGB7cn0KcDkxIDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMWVoiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiTFlaIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwOTIgPC0gRmVhdHVyZVBsb3QobXlvX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBOCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTMTAwQTgiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwOTEgfCBwOTIpIC8gcDg3CmBgYAoKTGFzdGx5LCB3ZSBzaG93IHRoYXQgY2x1c3RlciA2IGNvbnRhaW5zIG91ciB2YXJpb3VzIERDIHN1YnR5cGVzIHRocm91Z2ggaXRzIGV4cHJlc3Npb24gb2YgRkNFUjFBLCBhIGNhbm9uaWNhbCBkZW5kcml0aWMgY2VsbCBtYXJrZXIuIAoKYGBge3J9CnA5MyA8LSBGZWF0dXJlUGxvdChteW9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRkNFUjFBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkZDRVIxQSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDkzIC8gcDg3CmBgYAoKIyMjIyBSZWNsdXN0ZXJpbmcKCldlJ2xsIHN0YXJ0IHdpdGggdGhlIE1hY3JvcGhhZ2VzICYgTW9ub2N5dGVzLCBzaW5jZSB0aGUgREMgcG9wdWxhdGlvbnMgYXJlIHNtYWxsIGFuZCBhcmUgYmVzdCBkZWFsdCB3aXRoIG9uIHRoZWlyIG93bi4gCgpgYGB7cn0KbXlvX3JlY2x1c3QgPC0gUmVjbHVzdGVyQ2VsbHMobXlvX3R1bW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guY2x1c3QgPSBjKDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVyZ2UuY2x1c3RlcnMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgay52YWxzID0gYyg0MCwgNTAsIDYwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjIsIC4zLCAuNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLkhWRyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKZGNfcmVjbHVzdCA8LSBSZWNsdXN0ZXJDZWxscyhteW9fdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDIwLCAzMCwgNDAsIDUwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMywgLjQsIC41KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5IVkcgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubi5tZXRyaWMgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKYGBgCgpXZSdsbCBhZ2FpbiBydW4gRml0LVNORSBvbiBvdXIgcmVjbHVzdGVyZWQgY2VsbHMuIAoKYGBge3J9Cm1vbm9fdHVtb3JfcGMgPC0gRW1iZWRkaW5ncyhteW9fcmVjbHVzdCwgInBjYSIpCmRjX3R1bW9yX3BjIDwtIEVtYmVkZGluZ3MoZGNfcmVjbHVzdCwgInBjYSIpCmBgYAoKYGBge3B5dGhvbn0KIyBpbXBvcnQgZGF0YQptb25vX3BjID0gci5tb25vX3R1bW9yX3BjCmRjX3BjID0gci5kY190dW1vcl9wYwojIEZpdC1TTkUgLSBtb25vY3l0ZXMgJiBtYWNyb3BoYWdlcwphZmZpbl9tb25vID0gUGVycGxleGl0eUJhc2VkTk4obW9ub19wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKG1vbm9fcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfbW9ubyA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fbW9ubywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9tb25vMSA9IHRzbmVfbW9uby5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249MTAsIG1vbWVudHVtPTAuNikKZW1iZWRfbW9ubzIgPSBlbWJlZF9tb25vMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQojIEZpdC1TTkUgLSBEQwphZmZpbl9kYyA9IFBlcnBsZXhpdHlCYXNlZE5OKGRjX3BjLCBwZXJwbGV4aXR5PTMwLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKGRjX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX2RjID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9kYywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9kYzEgPSB0c25lX2RjLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC42KQplbWJlZF9kYzIgPSBlbWJlZF9kYzEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpXZSBwdWxsIHRoZSByZXN1bHRzIGJhY2sgaW50byBSIGFuZCB2aXN1YWxpemUgdGhlbS4gCgpgYGB7cn0KZW1iZWRfbW9ubyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfbW9ubzIpCnJvd25hbWVzKGVtYmVkX21vbm8pIDwtIGNvbG5hbWVzKG15b19yZWNsdXN0KQpteW9fcmVjbHVzdEByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gbXlvX3JlY2x1c3RAcmVkdWN0aW9ucyR0c25lCm15b19yZWNsdXN0QHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9tb25vLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDk0IDwtIERpbVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA5NApgYGAKCmBgYHtyfQplbWJlZF9kYyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfZGMyKQpyb3duYW1lcyhlbWJlZF9kYykgPC0gY29sbmFtZXMoZGNfcmVjbHVzdCkKZGNfcmVjbHVzdEByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gZGNfcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmUKZGNfcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwOTUgPC0gRGltUGxvdChkY19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwOTUKYGBgCgojIyMjIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKIyMjIyMgTW9ub2N0eWVzLCBNYWNyb3BoYWdlcywgJiBOZXV0cm9waGlscwoKRmlyc3Qgd2UgSUQgdGhlIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgMiB1c2luZyBTMTAwQTggYW5kIFMxMDBBOSAtIG1hcmtlciBnZW5lcyB1c2VkIGJ5IEVseWFkYSAqZXQgYWwqLiAKCmBgYHtyfQpwOTYgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUzEwMEE4IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlMxMDBBOCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDk3IDwtIEZlYXR1cmVQbG90KG15b19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBOSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTMTAwQTkiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwOTYgfCBwOTcpIC8gcDk0CmBgYAoKV2UgY2FuIGlkZW50aWZ5IHRoZSBjbGFzc2ljYWwgbW9ub2N5dGVzIGluIGNsdXN0ZXIgMSB0aHJvdWdoIHRoZWlyIGV4cHJlc3Npb24gb2YgQ0QxNCBhbmQgbGFjayBvZiBleHByZXNzaW9uIG9mIENEMTYgYWthIEZDR1IzQSwgZXhwcmVzc2lvbiBvZiB3aGljaCwgYWxvbmdzaWRlIHRoYXQgb2YgTVM0QTcsIHJldmVhbHMgdGhlIGdyb3VwIG9mIENEMTYrIG1vbm9jeXRlcyBpbiBjbHVzdGVyIDQuIEZpbmFsbHksIGV4cHJlc3Npb24gb2YgdGhvc2UgZ2VuZXMgW2FzIHdlbGwgYXMgUzEwMEExMF0oaHR0cHM6Ly93d3cuZnJvbnRpZXJzaW4ub3JnL2FydGljbGVzLzEwLjMzODkvZmltbXUuMjAxOS4wMjAzNS9mdWxsI0IzKSBhbGxvd3MgdXMgdG8gZGVmaW5lZCBjbHVzdGVyIDUgYXMgY29udGFpbmluZyBpbnRlcm1lZGlhdGUgbW9ub2N5dGVzLiAKCmBgYHtyfQpwOTggPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDE0IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwOTkgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRkNHUjNBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkZDR1IzQSAoQ0QxNikiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDAgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTVM0QTciLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiTVM0QTciKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDEgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUzEwMEExMCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTMTAwQTEwIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDk4IHwgcDk5IHwgcDEwMCB8IHAxMDEpIC8gcDk0CmBgYAoKRXhwcmVzc2lvbiBvZiBDMVFBLCBBUE9FLCBhbmQgU1BQMSBzaG93IHVzIHRoZSByZXNpZGVudCBhbmQgYWx0ZXJuYXRpdmVseSBhY3RpdmF0ZWQgbWFjcm9waGFnZXMgaW4gY2x1c3RlcnMgMCBhbmQgMywgcmVzcGVjdGl2ZWx5LiAKCmBgYHtyfQpwMTAyIDwtIEZlYXR1cmVQbG90KG15b19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkMxUUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDMVFBIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTAzIDwtIEZlYXR1cmVQbG90KG15b19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkFQT0UiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJBUE9FIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTA0IDwtIEZlYXR1cmVQbG90KG15b19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlNQUDEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTUFAxIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDEwMiB8IHAxMDMgfCBwMTA0KSAvIHA5NApgYGAKCldlIGFkZCBjZWxsIGxhYmVscyB0byBvdXIgYFNldXJhdGAgb2JqZWN0LCB0aGVuIHdlJ3JlIG9mZiB0byB0aGUgRENzLiAKCmBgYHtyfQpteW9fcmVjbHVzdCRsYWJlbCA8LSBjYXNlX3doZW4obXlvX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDAgfiAiUmVzaWRlbnQgTWFjcm9waGFnZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXlvX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiQ2xhc3NpY2FsIE1vbm9jeXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJOZXV0cm9waGlsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMyB+ICJBbHQuIEFjdGl2YXRlZCBNYWNyb3BoYWdlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJDRDE2KyBNb25vY3l0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXlvX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDUgfiAiSW50ZXJtZWRpYXRlIE1vbm9jeXRlIikKSWRlbnRzKG15b19yZWNsdXN0KSA8LSAibGFiZWwiCmBgYAoKIyMjIyMgRGVuZHJpdGljIENlbGxzCgpXZSBjYW4gdXNlIENMRUM5QSB0byBhbm5vdGF0ZSB0aGUgY0RDMSBwb3B1bGF0aW9uIGluIGNsdXN0ZXIgNS4gCgpgYGB7cn0KcDEwNSA8LSBGZWF0dXJlUGxvdChkY19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNMRUM5QSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkNMRUM5QSIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDEwNSAvIHA5NQpgYGAKCkhpZ2ggYW5kIGxvdyBleHByZXNzaW9uIG9mIENEMUEgYW5kIENEMjA3IHJldmVhbCB0aGUgTGFuZ2VyaGFucy1saWtlIERDQiBhbmQgRENBIGNlbGxzIGluIGNsdXN0ZXJzIDMgYW5kIDQsIHJlc3BlY3RpdmVseS4gCgpgYGB7cn0KcDEwNiA8LSBGZWF0dXJlUGxvdChkY19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEMUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDFBIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTA3IDwtIEZlYXR1cmVQbG90KGRjX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QyMDciLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDIwNyIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMDYgfCBwMTA3KSAvIHA5NQpgYGAKCk5leHQgd2UgdXNlIExBTVAzIHRvIGlkZW50aWZ5IHRoZSBhY3RpdmF0ZWQgRENzIGluIGNsdXN0ZXIgNi4gCgpgYGB7cn0KcDEwOCA8LSBGZWF0dXJlUGxvdChkY19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkxBTVAzIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiTEFNUDMiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDggLyBwOTUKYGBgCgpMYXN0bHksIHdlIHVzZSBleHByZXNzaW9uIG9mIHR3byBbY2Fub25pY2FsIGNEQzIgbWFya2VyIGdlbmVzIC8gdHJhbnNjcmlwdGlvbiBmYWN0b3JzXShodHRwczovL29ubGluZWxpYnJhcnkud2lsZXkuY29tL2RvaS9wZGYvMTAuMTExMS9pbW0uMTI4ODgpIHRvIGlkZW50aWZ5IGNsdXN0ZXJzIDAsIDEsIGFuZCAyIGFzIGNEQzIgY2VsbHMsIHdoaWNoIGFyZSBzcGxpdCBieSBzYW1wbGUgSUQuIAoKYGBge3J9CnAxMDkgPC0gRmVhdHVyZVBsb3QoZGNfcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDTEVDMTBBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTEwIDwtIEZlYXR1cmVQbG90KGRjX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiS0xGNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDExMSA8LSBEaW1QbG90KGRjX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAic2FtcGxlIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiU2FtcGxlIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDEwOSB8IHAxMTAgfCBwMTExKSAvIHA5NQpgYGAKCldlIGFkZCBmaW5hbCBzdWJjbHVzdGVyIGNlbGwgdHlwZSBsYWJlbHMgdG8gb3VyIGBTZXVyYXRgIG9iamVjdCwgdGhlbiB3ZSdyZSBvZmYgdG8gdGhlIGFkamFjZW50IG5vcm1hbCBteWVsb2lkIGNlbGxzLiAKCmBgYHtyfQpkY19yZWNsdXN0JGxhYmVsIDwtIGNhc2Vfd2hlbihkY19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAwIH4gImNEQzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJjREMyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRjX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiY0RDMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkY19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIkxhbmdlcmhhbnMtbGlrZSBEQ0IiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJMYW5nZXJoYW5zLWxpa2UgRENBIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRjX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDUgfiAiY0RDMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkY19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIkFjdGl2YXRlZCBEQyIpCklkZW50cyhkY19yZWNsdXN0KSA8LSAibGFiZWwiCmBgYAoKIyMjIyBWaXN1YWxpemF0aW9uCgojIyMjIyBNb25vY3l0ZXMgJiBOZXV0cm9waGlscwoKYGBge3J9CnAxMTIgPC0gRGltUGxvdChteW9fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMTEyCmBgYAoKSGVyZSdzIHRoZSBtYXJrZXIgZ2VuZXMuIAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9Cm15b19yZWNsdXN0X21hcmtlcnMyIDwtIEZpbmRBbGxNYXJrZXJzKG15b19yZWNsdXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UgPSAiTXllbG9pZCBUdW1vciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMmZjX2N1dG9mZiA9IDEpCnRvcDVfbXlvX3JlY2x1c3RfbWFya2VycyA8LSBteW9fcmVjbHVzdF9tYXJrZXJzMiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnAxMTMgPC0gRG90UGxvdChteW9fcmVjbHVzdCwgZmVhdHVyZXMgPSB1bmlxdWUodG9wNV9teW9fcmVjbHVzdF9tYXJrZXJzJGdlbmUpLCBkb3Quc2NhbGUgPSAxNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gcGFsZXR0ZWVyX2QoIndlc2FuZGVyc29uOjpaaXNzb3UxIikpICsKICAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIikgKyAKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gMTYsIHZqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgCiAgICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIGJhcmhlaWdodCA9IHVuaXQoMywgdW5pdHMgPSAiY20iKSwgdGl0bGUuaGp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnAxMTMKYGBgCgojIyMjIyBEQ3MKCmBgYHtyfQpwMTE0IDwtIERpbVBsb3QoZGNfcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwMTE0CmBgYAoKSGVyZSdzIHRoZSBtYXJrZXIgZ2VuZXMuIAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9CmRjX3JlY2x1c3RfbWFya2VyczIgPC0gRmluZEFsbE1hcmtlcnMoZGNfcmVjbHVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UgPSAiREMgVHVtb3IiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMmZjX2N1dG9mZiA9IDEpCnRvcDVfZGNfcmVjbHVzdF9tYXJrZXJzIDwtIGRjX3JlY2x1c3RfbWFya2VyczIgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhhdmdfbG9nMkZDKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZV9oZWFkKG4gPSA1KQpwMTE1IDwtIERvdFBsb3QoZGNfcmVjbHVzdCwgZmVhdHVyZXMgPSB1bmlxdWUodG9wNV9kY19yZWNsdXN0X21hcmtlcnMkZ2VuZSksIGRvdC5zY2FsZSA9IDE1KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgIGxhYnMoY29sb3IgPSAiRXhwcmVzc2lvbiIsIHNpemUgPSAiJSBFeHByZXNzZWQiKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxNiwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDExNQpgYGAKCiMjIyBBZGphY2VudCBOb3JtYWwKCldlIGhhdmUgdGhlIHNhbWUgZm91ciBjbHVzdGVycyBhcyBpbiB0aGUgdHVtb3IgdGlzc3VlIC0gMSwgMiwgJiA3IC0gYW5kIHdlJ2xsIHJ1biB0aGUgc2FtZSBhbmFseXNpcyBzdGVwcy4gIAoKYGBge3J9Cm15b19ub3JtIDwtIHN1YnNldChwZGFjLCBzdWJzZXQgPSBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDEsIDIsIDcpICYgY29uZGl0aW9uID09ICJBZGpOb3JtIikKYGBgCgojIyMjIFJlY2x1c3RlcmluZwoKYGBge3J9Cm15b19ub3JtX3JlY2x1c3QgPC0gUmVjbHVzdGVyQ2VsbHMobXlvX25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gYygxLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXJnZS5jbHVzdGVycyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsudmFscyA9IGMoMjAsIDMwLCA0MCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjEsIC4yKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5IVkcgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpkY19ub3JtX3JlY2x1c3QgPC0gUmVjbHVzdGVyQ2VsbHMobXlvX25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guY2x1c3QgPSA3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDIwLCAzMCwgNDAsIDUwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uLnZhbHMgPSBjKC4zLCAuNCwgLjUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uSFZHID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubi5tZXRyaWMgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpCmBgYAoKRm9yIHRoZSBsYXN0IHRpbWUsIHdlIHJ1biBGaXQtU05FIGluIG9yZGVyIHRvIG9idGFpbiBhIGJldHRlciBlbWJlZGRpbmcuIAoKYGBge3J9Cm1vbm9fbm9ybV9wYyA8LSBFbWJlZGRpbmdzKG15b19ub3JtX3JlY2x1c3QsICJwY2EiKQpkY19ub3JtX3BjIDwtIEVtYmVkZGluZ3MoZGNfbm9ybV9yZWNsdXN0LCAicGNhIikKYGBgCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCm1vbm9fcGMgPSByLm1vbm9fbm9ybV9wYwpkY19wYyA9IHIuZGNfbm9ybV9wYwojIEZpdC1TTkUgLSBtb25vY3l0ZXMKYWZmaW5fbW9ubyA9IFBlcnBsZXhpdHlCYXNlZE5OKG1vbm9fcGMsIHBlcnBsZXhpdHk9MzAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShtb25vX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX21vbm8gPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX21vbm8sIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWRfbW9ubzEgPSB0c25lX21vbm8ub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTEwLCBtb21lbnR1bT0wLjYpCmVtYmVkX21vbm8yID0gZW1iZWRfbW9ubzEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKIyBGaXQtU05FIC0gREMKYWZmaW5fZGMgPSBQZXJwbGV4aXR5QmFzZWROTihkY19wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKGRjX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX2RjID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9kYywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9kYzEgPSB0c25lX2RjLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj04LCBtb21lbnR1bT0wLjYpCmVtYmVkX2RjMiA9IGVtYmVkX2RjMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKCldlIHB1bGwgdGhlIHJlc3VsdHMgYmFjayBpbnRvIFIgYW5kIHZpc3VhbGl6ZSB0aGVtLiAKCmBgYHtyfQplbWJlZF9tb25vIDwtIGFzLm1hdHJpeChweSRlbWJlZF9tb25vMikKcm93bmFtZXMoZW1iZWRfbW9ubykgPC0gY29sbmFtZXMobXlvX25vcm1fcmVjbHVzdCkKbXlvX25vcm1fcmVjbHVzdEByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gbXlvX25vcm1fcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmUKbXlvX25vcm1fcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfbW9ubywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbCA9IFRSVUUpCnAxMTYgPC0gRGltUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAxMTYKYGBgCgpgYGB7cn0KZW1iZWRfZGMgPC0gYXMubWF0cml4KHB5JGVtYmVkX2RjMikKcm93bmFtZXMoZW1iZWRfZGMpIDwtIGNvbG5hbWVzKGRjX25vcm1fcmVjbHVzdCkKZGNfbm9ybV9yZWNsdXN0QHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBkY19ub3JtX3JlY2x1c3RAcmVkdWN0aW9ucyR0c25lCmRjX25vcm1fcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwMTE3IDwtIERpbVBsb3QoZGNfbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAxMTcKYGBgCgojIyMjIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKIyMjIyMgTW9ub2N5dGVzLCBNYWNyb3BoYWdlcywgJiBOZXV0cm9waGlscwoKV2UgdXNlIGhpZ2ggUzEwMEE4IGFuZCBTMTAwQTkgZXhwcmVzc2lvbiB0byBkZWZpbmUgdGhlIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgNC4gCgpgYGB7cn0KcDExOCA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBOCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDExOSA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBOSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMTggfCBwMTE5KSAvIHAxMTYKYGBgCgpOZXh0IHVwIGFyZSB0aGUgY2xhc3NpY2FsIG1vbm9jeXRlcyBpbiBjbHVzdGVycyAwIGFuZCAzLCBzcGxpdCBieSBzYW1wbGUuIAoKYGBge3J9CnAxMjAgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMWVoiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMjEgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDE0IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTIyIDwtIERpbVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJzYW1wbGUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTYW1wbGUiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMTIwIHwgcDEyMSB8IHAxMjIpIC8gcDExNgpgYGAKCkMxUUEgYW5kIEFQT0Ugc2hvdyB1cyB0aGUgcmVzaWRlbnQgbWFjcm9waGFnZXMgaW4gY2x1c3RlcnMgMSBhbmQgMi4gCgpgYGB7cn0KcDEyMyA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkMxUUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMjQgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJBUE9FIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDEyMyB8IHAxMjQpIC8gcDExNgpgYGAKCkxhc3RseSwgaXQgc2VlbXMgd2UgaGF2ZSBhIHNtYWxsIGdyb3VwIG9mIENEOCsgVCBjZWxscyBpbiBjbHVzdGVyIDUgdGhhdCBzbnVjayBpbnRvIHRoZSBteWVsb2lkIGNsdXN0ZXIsIGFzIGRlZmluZWQgYnkgdGhlaXIgZXhwcmVzc2lvbiBvZiBDRDNEIChtYXJraW5nIHRoZW0gYXMgTksgLyBUIGNlbGxzKSwgYW5kIENEOEEgJiBOS0c3LiBJIGRvbid0IGJlbGlldmUgdGhleSdyZSBOSyBjZWxscyBhcyB0aGV5IGRvIG5vdCBleHByZXNzIFBSRjEgb3IgR1pNQi4gCgpgYGB7cn0KcDEyNSA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEM0QiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMjYgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDhBIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTI3IDwtIEZlYXR1cmVQbG90KG15b19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTktHNyIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMjUgfCBwMTI2IHwgcDEyNykgLyBwMTE2CmBgYAoKV2UgYWRkIGxhYmVscyB0byBvdXIgY2x1c3RlcnMuIAoKYGBge3J9Cm15b19ub3JtX3JlY2x1c3QkbGFiZWwgPC0gY2FzZV93aGVuKG15b19ub3JtX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDAgfiAiQ2xhc3NpY2FsIE1vbm9jeXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15b19ub3JtX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiUmVzaWRlbnQgTWFjcm9waGFnZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fbm9ybV9yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAyIH4gIlJlc2lkZW50IE1hY3JvcGhhZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXlvX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMyB+ICJDbGFzc2ljYWwgTW9ub2N5dGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXlvX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJOZXV0cm9waGlsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXlvX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gNSB+ICJDRDgrIFQiKQpJZGVudHMobXlvX25vcm1fcmVjbHVzdCkgPC0gImxhYmVsIgpgYGAKCiMjIyMjIERlbmRyaXRpYyBDZWxscwoKV2UgYW5ub3RhdGUgY2x1c3RlciAxIGFzIGNvbnZlbnRpb25hbCBEQzEgYW5kIGNsdXN0ZXIgMCBhcyBjb252ZW50aW9uYWwgREMyIHRocm91Z2ggbXV0dWFsbHkgZXhjbHVzaXZlIGV4cHJlc3Npb24gb2YgdGhlIGNhbm9uaWNhbCBtYXJrZXJzIENMRUM5QSBhbmQgQ0xFQzEwQSwgcmVzcGVjdGl2ZWx5LiAKCmBgYHtyfQpwMTI4IDwtIEZlYXR1cmVQbG90KGRjX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDTEVDOUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMjkgPC0gRmVhdHVyZVBsb3QoZGNfbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNMRUMxMEEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMTI4IHwgcDEyOSkgLyBwMTE3CmBgYAoKTGFiZWxzIGFyZSBhZGRlZCB0byBvdXIgYWRqYWNlbnQgbm9ybWFsIHRpc3N1ZSBEQyBgU2V1cmF0YCBvYmplY3QuIAoKYGBge3J9CmRjX25vcm1fcmVjbHVzdCRsYWJlbCA8LSBjYXNlX3doZW4oZGNfbm9ybV9yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAwIH4gImNEQzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkY19ub3JtX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiY0RDMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRjX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJjREMxIikKSWRlbnRzKGRjX25vcm1fcmVjbHVzdCkgPC0gImxhYmVsIgpgYGAKCiMjIyMgVmlzdWFsaXphdGlvbgoKIyMjIyMgTW9ub2N5dGVzLCBNYWNyb3BoYWdlcywgJiBOZXV0cm9waGlscwoKSGVyZSBhcmUgdGhlIGZpbmFsIGFubm90YXRpb25zIGZvciB0aGUgYWRqYWNlbnQgbm9ybWFsIHRpc3N1ZSBteWVsb2lkIHBvcHVsYXRpb24uIAoKYGBge3J9CnAxMzAgPC0gRGltUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAxMzAKYGBgCgpBbmQgaGVyZSdzIHRoZWlyIG1hcmtlciBnZW5lcy4gCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0KbXlvX25vcm1fcmVjbHVzdF9tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2VycyhteW9fbm9ybV9yZWNsdXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHNvdXJjZSA9ICJNeWVsb2lkIEFkamFjZW50IE5vcm1hbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyZmNfY3V0b2ZmID0gMSkKdG9wNV9teW9fbm9ybV9yZWNsdXN0X21hcmtlcnMgPC0gbXlvX25vcm1fcmVjbHVzdF9tYXJrZXJzMiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnAxMzEgPC0gRG90UGxvdChteW9fbm9ybV9yZWNsdXN0LCBmZWF0dXJlcyA9IHVuaXF1ZSh0b3A1X215b19ub3JtX3JlY2x1c3RfbWFya2VycyRnZW5lKSwgZG90LnNjYWxlID0gMTUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDE2LCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImNlbnRlciIsIAogICAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLCAKICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLCAKICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCBiYXJoZWlnaHQgPSB1bml0KDMsIHVuaXRzID0gImNtIiksIHRpdGxlLmhqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgIHNpemUgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUpKQpwMTMxCmBgYAoKIyMjIyMgRGVuZHJpdGljIENlbGxzCgpIZXJlJ3MgdGhlIGZpbmFsIERDIGFubm90YXRpb25zLgoKYGBge3J9CnAxMzIgPC0gRGltUGxvdChkY19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDEzMgpgYGAKCkFuZCBoZXJlIGFyZSB0aGVpciBtYXJrZXIgZ2VuZXMuIAoKYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTN9CmRjX25vcm1fcmVjbHVzdF9tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2VycyhkY19ub3JtX3JlY2x1c3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UgPSAiREMgQWRqYWNlbnQgTm9ybWFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMmZjX2N1dG9mZiA9IDEpCnRvcDVfZGNfbm9ybV9yZWNsdXN0X21hcmtlcnMgPC0gZGNfbm9ybV9yZWNsdXN0X21hcmtlcnMyICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2VfaGVhZChuID0gNSkKcDEzMyA8LSBEb3RQbG90KGRjX25vcm1fcmVjbHVzdCwgZmVhdHVyZXMgPSB1bmlxdWUodG9wNV9kY19ub3JtX3JlY2x1c3RfbWFya2VycyRnZW5lKSwgZG90LnNjYWxlID0gMTUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDE2LCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImNlbnRlciIsIAogICAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLCAKICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLCAKICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCBiYXJoZWlnaHQgPSB1bml0KDMsIHVuaXRzID0gImNtIiksIHRpdGxlLmhqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgIHNpemUgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUpKQpwMTMzCmBgYAoKIyBDb25jbHVzaW9ucwoKYFNDSVNTT1JTYCB3YXMgYWJsZSB0bywgd2l0aCB0aGUgaGVscCBvZiBzZXZlcmFsIG90aGVyIG1ldGhvZHMsIGlkZW50aWZ5IG1hbnkgY2VsbHR5cGVzLCBpbmNsdWRpbmcgY2VsbHR5cGVzIHRoYXQgd2VyZSBub3QgZGlzY292ZXJlZCBpbiB0aGUgb3JpZ2luYWwgYW5hbHlzaXMgZG9uZSBieSBFbHlhZGEgKmV0IGFsKi4gSXQgYWxzbyBkaWQgc28gaW4gYSByZXByb2R1Y2libGUgd2F5LCB3aGljaCBpcyBwYXJhbW91bnQgaW4gdGhlIGVyYSBvZiBjb21wdXRhdGlvbmFsIGJpb2xvZ3kuIFdlIGJlbGlldmUgdGhpcyBhbmFseXNpcyBzaG93cyB0aGUgcHJvbWlzZSBvZiBgU0NJU1NPUlNgIGFzIGEgdmFsdWFibGUgcGllY2Ugb2YgdGhlIHNjUk5BLXNlcSBkYXRhIGV4cGxvcmF0aW9uIGFuZCBhbm5vdGF0aW9uIHByb2Nlc3Nlcy4gCgojIFNhdmUgRGF0YSAmIEZpZ3VyZXMKCkZpcnN0IHdlJ2xsIHNhdmUgdGhlIGZpbmFsIFBEQUMgb2JqZWN0LiAKCmBgYHtyLCBldmFsPUZBTFNFfQpzYXZlUkRTKHBkYWMsICJ+L0Rlc2t0b3AvRGF0YS9FbHlhZGEuUmRzIikKc2F2ZVJEUyhua3RfdHVtb3IsICJ+L0Rlc2t0b3AvRGF0YS9FbHlhZGFfbmt0X3R1bW9yLlJkcyIpCnNhdmVSRFMobmt0X25vcm0sICJ+L0Rlc2t0b3AvRGF0YS9FbHlhZGFfbmt0X2Fkak5vcm0uUmRzIikKc2F2ZVJEUyhmaWJybywgIn4vRGVza3RvcC9EYXRhL0VseWFkYV9maWJyby5SZHMiKQpzYXZlUkRTKGR1Y3RhbCwgIn4vRGVza3RvcC9EYXRhL0VseWFkYV9kdWN0YWwuUmRzIikKc2F2ZVJEUyhteW9fcmVjbHVzdCwgIn4vRGVza3RvcC9EYXRhL0VseWFkYV9teWVsb2lkX3R1bW9yLlJkcyIpCnNhdmVSRFMobXlvX25vcm1fcmVjbHVzdCwgIn4vRGVza3RvcC9EYXRhL0VseWFkYV9teWVsb2lkX2Fkak5vcm0uUmRzIikKc2F2ZVJEUyhkY19yZWNsdXN0LCAifi9EZXNrdG9wL0RhdGEvRWx5YWRhX0RDX3R1bW9yLlJkcyIpCnNhdmVSRFMoZGNfbm9ybV9yZWNsdXN0LCAifi9EZXNrdG9wL0RhdGEvRWx5YWRhX0RDX2Fkak5vcm0uUmRzIikKYGBgCgpOZXh0IHdlJ2xsIGNyZWF0ZSBhIGZpbmFsIHRhYmxlIG9mIGFsbCB0aGUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGZyb20gdGhlIGBTQ0lTU09SU2AgcmVzdWx0cyBmb3IgZWFjaCBjZWxsdHlwZSwgYW5kIHNhdmUgdGhlbSBpbnRvIG9uZSBsYXJnZSBFeGNlbCBkb2N1bWVudC4gCgpgYGB7ciwgZXZhbD1GQUxTRX0KY2FmX21hcmtlcnMgJT4lIAogIGJpbmRfcm93cyhua3RfdHVtb3JfbWFya2VyczIpICU+JSAKICBiaW5kX3Jvd3Mobmt0X25vcm1fbWFya2VyczIpICU+JSAKICBiaW5kX3Jvd3MoZHVjdGFsX21hcmtlcnMyKSAlPiUgCiAgYmluZF9yb3dzKG15b19yZWNsdXN0X21hcmtlcnMyKSAlPiUgCiAgYmluZF9yb3dzKGRjX3JlY2x1c3RfbWFya2VyczIpICU+JSAKICBiaW5kX3Jvd3MobXlvX25vcm1fcmVjbHVzdF9tYXJrZXJzMikgJT4lIAogIGJpbmRfcm93cyhkY19ub3JtX3JlY2x1c3RfbWFya2VyczIpIC0+IFNDSVNTT1JTX2RlX3Jlc3VsdHMKb3Blbnhsc3g6OndyaXRlLnhsc3goU0NJU1NPUlNfZGVfcmVzdWx0cywgZmlsZSA9ICIuL0RhdGEvRWx5YWRhX1NDSVNTT1JTX01hcmtlcl9HZW5lcy54bHN4IikKYGBgCgpXZSdsbCBjcmVhdGUgYSBxdWljayBjb252ZW5pZW5jZSBmdW5jdGlvbiB0byBoZWxwIHVzIHNhdmUgdGhlIGZpZ3VyZXMuCgpgYGB7cn0KU2F2ZUZpZ3VyZSA8LSBmdW5jdGlvbihteS5wbG90ID0gTlVMTCwgbmFtZSA9IE5VTEwsIGhlaWdodCA9IDgsIHdpZHRoID0gOCkgewogIGlmIChpcy5udWxsKHBsb3QpIHwgaXMubnVsbChuYW1lKSkgc3RvcCgiWW91IGZvcmdvdCBzb21lIGFyZ3VtZW50cy4iKQogICMgc2F2ZSBmaWd1cmUgYXMgaXMgLSB3LyBheGlzIGxhYmVscywgdGl0bGVzLCBldGMuIAogIGRpciA8LSAifi9EZXNrdG9wL1IvU0NJU1NPUlMvdmlnbmV0dGVzL2ZpZ3VyZXNfc3VwcC9FbHlhZGEiCiAgZ2dzYXZlKG15LnBsb3QsIAogICAgICAgICBmaWxlbmFtZSA9IHBhc3RlMChuYW1lLCAiLnBkZiIpLCAKICAgICAgICAgZGV2aWNlID0gInBkZiIsIAogICAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICAgIHBhdGggPSBkaXIsIAogICAgICAgICBoZWlnaHQgPSBoZWlnaHQsIAogICAgICAgICB3aWR0aCA9IHdpZHRoKSAKICAjIHNhdmUgImJsYW5rIiBmaWd1cmUgdy8gbm8gbGFiZWxzLCBsZWdlbmRzLCBldGMuCiAgZGlyIDwtICJ+L0Rlc2t0b3AvUi9TQ0lTU09SUy92aWduZXR0ZXMvZmlndXJlc19wdWIvRWx5YWRhIgogIHBsb3RfYmxhbmsgPC0gbXkucGxvdCArIAogICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgZ2dzYXZlKHBsb3RfYmxhbmssIAogICAgICAgICBmaWxlbmFtZSA9IHBhc3RlMChuYW1lLCAiLnBkZiIpLCAKICAgICAgICAgZGV2aWNlID0gInBkZiIsIAogICAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICAgIHBhdGggPSBkaXIsIAogICAgICAgICBoZWlnaHQgPSBoZWlnaHQsIAogICAgICAgICB3aWR0aCA9IHdpZHRoKSAKfQpgYGAKClRoaXMgc2VjdGlvbiBpc24ndCB3b3J0aCByZWFkaW5nOyBpdCdzIGhlcmUgc29sZWx5IHRvIHByb3ZlIHRoYXQgdGhlIGZpZ3VyZXMgd2UgcHJlc2VudCBpbiBvdXIgcHVibGljYXRpb24gd2VyZSBkeW5hbWljYWxseSBnZW5lcmF0ZWQgZHVyaW5nIHRoZSBrbml0dGluZyBvZiB0aGlzIGRvY3VtZW50LgoKYGBge3IsIGV2YWw9RkFMU0V9ClNhdmVGaWd1cmUobXkucGxvdCA9IHAwLCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc190U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEsIG5hbWUgPSAiU2V1cmF0X0NsdXN0ZXJzX1NpbGhvdWV0dGVfU2NvcmVzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDIsIG5hbWUgPSAiU2V1cmF0X0NsdXN0ZXJzX0RvdHBsb3QiLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDE4KQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMywgbmFtZSA9ICJTZXVyYXRfQ2x1c3RlcnNfVU1BUCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0LCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNSwgbmFtZSA9ICJTaW5nbGVSX3NjUk5BX0Fubm9zX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2LCBuYW1lID0gIlNpbmdsZVJfYnVsa1JOQV9Bbm5vc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNywgbmFtZSA9ICJDT05JQ1NtYXRfQW5ub3NfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDgsIG5hbWUgPSAiREVDT0RFUl9CYXNhbF9QREFDX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5LCBuYW1lID0gIkRFQ09ERVJfQ2xhc3NpY2FsX1BEQUNfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEwLCBuYW1lID0gIkRFQ09ERVJfRXhvY3JpbmVfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDExLCBuYW1lID0gIkRFQ09ERVJfRW5kb2NyaW5lX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMiwgbmFtZSA9ICJERUNPREVSX0ltbXVuZV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTMsIG5hbWUgPSAiREVDT0RFUl9Ob3JtYWxfU3Ryb21hX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxNCwgbmFtZSA9ICJERUNPREVSX0FjdGl2YXRlZF9TdHJvbWFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDE1LCBuYW1lID0gIkFsbF9DZWxsc19TdHJvbWFfQ09MMUExX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxNiwgbmFtZSA9ICJBbGxfQ2VsbHNfU3Ryb21hX0NPTDNBMV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTcsIG5hbWUgPSAiQWxsX0NlbGxzX1N0cm9tYV9MVU1fRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDE4LCBuYW1lID0gIkFsbF9DZWxsc19TdHJvbWFfRENOX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxOSwgbmFtZSA9ICJBbGxfQ2VsbHNfSGlnaGxpZ2h0X1N0cm9tYV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjAsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfU3Ryb21hX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAyMSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19TdHJvbWFfRW5kb3RoZWxpYWxfUExWQVAiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjIsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfU3Ryb21hX1Blcml2YXNjdWxhcl9SR1M1IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDIzLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX1N0cm9tYV9WQU1faUNBRiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAyNCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19TdHJvbWFfVkFNX215Q0FGIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDI1LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX1N0cm9tYV9WQU1fYXBDQUYiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfU3Ryb21hX0xhYmVsc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjcsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfU3Ryb21hX0RvdHBsb3QiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjgsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfQ0FGX0RvdHBsb3QiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjksIG5hbWUgPSAiQWxsX0NlbGxzX05LVF9DRDNEX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzMCwgbmFtZSA9ICJBbGxfQ2VsbHNfSGlnaGxpZ2h0X05LVF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzEsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzMiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfVHVtb3JfQ0Q0VF9JTDdSIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDMzLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9UdW1vcl9DRDRUX0NENjkiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzQsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX1RyZWdfSUwyUkEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzUsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX1RyZWdfRk9YUDMiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX1Byb2xpZl9UcmVnX1RPUDJBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDM3LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9UdW1vcl9NYXN0X1RQU0FCMSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzOCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfVHVtb3JfTktfTktHNyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzOSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfVHVtb3JfTktfUFJGMSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0MCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfVHVtb3JfQ0Q4VF9DRDhBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQxLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9UdW1vcl9DRDhUX0NEMiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0MiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfVHVtb3JfSW50ZXJtZWRpYXRlX01vbm9fTFlaIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQzLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9UdW1vcl9JbnRlcm1lZGlhdGVfTW9ub19ITEFEUkEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDQsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX0ludGVybWVkaWF0ZV9Nb25vX0NENzQiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDUsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX0ludGVybWVkaWF0ZV9Nb25vX0hMQURQQjEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX0xhYmVsc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDcsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX1R1bW9yX0RvdHBsb3QiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDgsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX0Fkak5vcm1fRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQ5LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9BZGpOb3JtX0NENFRfSUw3UiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1MCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfQWRqTm9ybV9DRDRUX01lbW9yeV9TMTAwQTQiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNTEsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX0Fkak5vcm1fQ0Q0VF9OYWl2ZV9DQ1I3IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDUyLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9BZGpOb3JtX0NEOFRfQ0Q4QSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1MywgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfQWRqTm9ybV9UcmVnX1RJR0lUIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDU0LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9BZGpOb3JtX1RyZWdfRk9YUDMiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNTUsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX0Fkak5vcm1fTktfUFJGMSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1NiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19OS1RfQWRqTm9ybV9OS19OS0c3IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDU3LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9BZGpOb3JtX1Byb2xpZl9UcmVnX1RPUDJBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDU4LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX05LVF9BZGpOb3JtX0xhYmVsc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNTksIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTktUX0Fkak5vcm1fRG90cGxvdCIsIGhlaWdodCA9IDYsIHdpZHRoID0gMTIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2MCwgbmFtZSA9ICJBbGxfQ2VsbHNfRHVjdGFsX0tSVDhfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDYxLCBuYW1lID0gIkFsbF9DZWxsc19IaWdobGlnaHRfRHVjdGFsX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2MiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EdWN0YWxfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDYzLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9WQU1fQ2xhc3NpY2FsMjVfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDY0LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9WQU1fQmFzYWwyNV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNjUsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX0xpcGlkX1Byb2NfQU5QRVAiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNjYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX0xpcGlkX1Byb2NfRkFCUDEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNjcsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX1NlY3JldG9yeV9TT0QzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDY4LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9TZWNyZXRvcnlfQ0ZUUiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2OSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EdWN0YWxfQ2xhc3NpY2FsMV9URkYxIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDcwLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9DbGFzc2ljYWwxX1RGRjIiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNzEsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX1NhbXBsZUlEIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDcyLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9DbGFzc2ljYWwyX0NSSVNQMyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA3MywgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EdWN0YWxfQ2xhc3NpY2FsMl9HQVRBNiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA3NCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EdWN0YWxfREVDT0RFUl9CYXNhbF9QREFDX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA3NSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EdWN0YWxfREVDT0RFUl9DbGFzc2ljYWxfUERBQ19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNzYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX0RFQ09ERVJfQkNfUmF0aW9fRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDc3LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9DT05JQ1NtYXRfQW5ub3NfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDc4LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0R1Y3RhbF9BY2luYXJfQ1RSQjIiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNzksIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX0xhYmVsc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODAsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRHVjdGFsX0RvdHBsb3QiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODEsIG5hbWUgPSAiQWxsX0NlbGxzX1BsYXNtYV9KQ0hBSU5fRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDgyLCBuYW1lID0gIkFsbF9DZWxsc19QbGFzbWFjeXRvaWRfRENfSVJGN19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODMsIG5hbWUgPSAiQWxsX0NlbGxzX0JfTVM0QTFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDg0LCBuYW1lID0gIkFsbF9DZWxsc19CX0NENzlBX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA4NSwgbmFtZSA9ICJBbGxfQ2VsbHNfVGlzc3VlX1R5cGVfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDg2LCBuYW1lID0gIkFsbF9DZWxsc19IaWdobGlnaHRfTXllbG9pZF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODcsIG5hbWUgPSAiQWxsX0NlbGxzX015ZWxvaWRfVHVtb3JfU3Vic2V0X0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA4OCwgbmFtZSA9ICJBbGxfQ2VsbHNfTXllbG9pZF9UdW1vcl9TdWJzZXRfQ0QxNF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODksIG5hbWUgPSAiQWxsX0NlbGxzX015ZWxvaWRfVHVtb3JfU3Vic2V0X0MxUUFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDkwLCBuYW1lID0gIkFsbF9DZWxsc19NeWVsb2lkX1R1bW9yX1N1YnNldF9TUFAxX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5MSwgbmFtZSA9ICJBbGxfQ2VsbHNfTXllbG9pZF9UdW1vcl9TdWJzZXRfTFlaX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5MiwgbmFtZSA9ICJBbGxfQ2VsbHNfTXllbG9pZF9UdW1vcl9TdWJzZXRfUzEwMEE4X0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5MywgbmFtZSA9ICJBbGxfQ2VsbHNfTXllbG9pZF9UdW1vcl9TdWJzZXRfRkNFUjFBX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5NCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX1R1bW9yX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5NSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EQ19UdW1vcl9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9UdW1vcl9OZXV0cm9waGlsX1MxMDBBOF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTcsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9UdW1vcl9OZXV0cm9waGlsX1MxMDBBOV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTgsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9UdW1vcl9DbGFzc2ljYWxfTW9ub19DRDE0X0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5OSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX1R1bW9yX0NEMTZfTW9ub19GQ0dSM0FfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEwMCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX1R1bW9yX0NEMTZfTW9ub19NUzRBN19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTAxLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfVHVtb3JfSW50ZXJtZWRpYXRlX01vbm9fTVM0QTdfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEwMiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX1R1bW9yX1Jlc2lkZW50X01hY3JvX0MxUUFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEwMywgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX1R1bW9yX0FsdF9BY3RpdmVfTWFjcm9fQVBPRV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTA0LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfVHVtb3JfQWx0X0FjdGl2ZV9NYWNyb19TUFAxX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMDUsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfY0RDMV9DTEVDOUFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEwNiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EQ19UdW1vcl9MYW5nZXJoYW5zX0RDX0NEMUFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEwNywgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EQ19UdW1vcl9MYW5nZXJoYW5zX0RDX0NEMjA3X0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMDgsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfQWN0aXZlX0RDX0xBTVAzX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMDksIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfY0RDMl9DTEVDMTBBX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTAsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfY0RDMl9LTEY0X0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTEsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfU2FtcGxlSURfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDExMiwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX1R1bW9yX0xhYmVsc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTEzLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfVHVtb3JfRG90cGxvdCIsIGhlaWdodCA9IDYsIHdpZHRoID0gMTIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTQsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfTGFiZWxzX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTUsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfVHVtb3JfRG90cGxvdCIsIGhlaWdodCA9IDYsIHdpZHRoID0gMTIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9BZGpOb3JtX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTcsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfQWRqTm9ybV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTE4LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfQWRqTm9ybV9OZXV0cm9waGlsX1MxMDBBOF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTE5LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfQWRqTm9ybV9OZXV0cm9waGlsX1MxMDBBOV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTIwLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfQWRqTm9ybV9DbGFzc2ljYWxfTW9ub19MWVpfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEyMSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX0Fkak5vcm1fQ2xhc3NpY2FsX01vbm9fREMxNF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTIyLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfQWRqTm9ybV9TYW1wbGVJRF9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTIzLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfQWRqTm9ybV9SZXNpZGVudF9NYWNyb19DMVFBX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMjQsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9BZGpOb3JtX1Jlc2lkZW50X01hY3JvX0FQT0VfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEyNSwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX0Fkak5vcm1fQ0Q4VF9DRDNEX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMjYsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9BZGpOb3JtX0NEOFRfQ0Q4QV9GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTI3LCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX015ZWxvaWRfQWRqTm9ybV9DRDhUX05LRzdfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEyOCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19EQ19BZGpOb3JtX2NEQzFfQ0xFQzlBX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMjksIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfQWRqTm9ybV9jREMyX0NMRUMxMEFfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEzMCwgbmFtZSA9ICJTQ0lTU09SU19DbHVzdGVyc19NeWVsb2lkX0Fkak5vcm1fTGFiZWxzX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMzEsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfTXllbG9pZF9BZGpOb3JtX0RvdHBsb3QiLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTMyLCBuYW1lID0gIlNDSVNTT1JTX0NsdXN0ZXJzX0RDX0Fkak5vcm1fTGFiZWxzX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMzMsIG5hbWUgPSAiU0NJU1NPUlNfQ2x1c3RlcnNfRENfQWRqTm9ybV9Eb3RwbG90IiwgaGVpZ2h0ID0gNiwgd2lkdGggPSAxMikKYGBgCgpBbmQgb2YgY291cnNlOgoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCg==